Skip to content

Latest commit

 

History

History
116 lines (82 loc) · 7.69 KB

0068-react-hooks.md

File metadata and controls

116 lines (82 loc) · 7.69 KB
  • Start Date: 2018-10-25
  • RFC PR: #68
  • React Issue: (leave this empty)

Summary

In this RFC, we propose introducing Hooks to React.

  • Hooks let you reuse logic between components without changing your component hierarchy.
  • Hooks let you split one component into smaller functions based on what pieces are related.
  • Hooks let you use React without classes.

Hooks are opt-in and 100% backwards-compatible. You can use Hooks side by side with your existing code.

This RFC is very detailed and inconvenient to read as a single Markdown file. Instead of condensing it and sacrificing important details, we decided to write our proposal in the form of documentation, and link to individual pages below. You can consider this documentation to be a part of the RFC, so please feel free to quote and discuss any content from it when commenting on the RFC.

Basic example

This example renders a counter. When you click the button, it increments the value:

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

This rest of this section is covered by:

Motivation

This section is covered by:

Detailed design

This section is covered by:

Some subtle aspects of this design that we especially appreciate:

  • Values returned from one Hook can be passed to another. For example, an effect can read the return value from useState because it is automatically in function scope.
  • Custom Hooks allow abstracting logic without any special involvement from React.
  • One variable per useState call instead of a single this.state object means fewer object property accesses that are hard for VMs to optimize.
  • State variables names (with useState) can be automatically minified.
  • No changes to build tooling are required.

Drawbacks

A non-exhaustive list of drawbacks of this Hooks design follows.

  • Introducing a new way to write components means more to learn and means confusion while both classes and functions are used.
  • The “Rules of Hooks”: in order to make Hooks work, React requires that Hooks are called unconditionally. Component authors may find it unintuitive that Hook calls can't be moved inside if statements, loops, and helper functions.
  • The “Rules of Hooks” can make some types of refactoring more difficult. For example, adding an early return to a component is no longer possible without moving all Hook calls to before that conditional.
  • Event handlers need to be recreated on each render in order to reference the latest copy of props and state, which reduces the effectiveness of PureComponent and React.memo.
  • It's possible for closures (like the ones passed to useEffect and useCallback) to capture old versions of props and state values. In particular, this happens if the “inputs” array is inadvertently missing one of captured variables. This can be confusing.
  • React relies on internal global state in order to determine which component is currently rendering when each Hook is called. This is “less pure” and may be unintuitive.
  • React.memo (as a replacement for shouldComponentUpdate) only has access to the old and new props; there's no easy way to skip rerendering for an inconsequential state update.
  • useState uses a tuple return value that requires typing the same name twice to declare a state field (like const [rhinoceros, setRhinoceros] = useState(null);), which may be cumbersome for long names.
  • useState uses the overloaded type () => T | T to support lazy initialization. But when storing a function in state (that is, when T is a function type) you must always use a lazy initializer useState(() => myFunction) because the types are indistinguishable at runtime. Similarly, the functional updater form must be used when setting state to a new function value.

Alternatives

Possible alternatives follow. In our opinion, none of these cleanly solve all the problems that Hooks do.

Adoption strategy

We're planning to recommend a gradual adoption strategy for Hooks. Hooks don't break existing patterns, and they can be used side by side with class components. It's possible that codemod could be written to automatically convert simple class components to use Hooks instead, but none is currently planned.

How we teach this

The documentation linked above is our best attempt at teaching this. Over time we expect that we'll integrate the Hooks documentation with the main concept docs instead of having it in a separate section.

Credits and prior art

Hooks synthesize ideas from several different sources:

Sebastian Markbåge came up with the original design for Hooks, later refined by Andrew Clark, Sophie Alpert, Dominic Gannaway, and other members of the React team.