recorded decision · public · no signup

accepted2026-06-22reactjs/rfcs

Summary

What was chosen

  • React introduces Hooks to enable state and effects in functional components.adr

What was ruled out· 1

  • The status quo of supporting state and effects only in class components was considered and not chosen.adr

Constraints

  • Hooks must be opt-in and 100% backwards-compatible with existing React code.adr

Consequences

  • Hooks allow developers to use React and its features without relying on class components.adr
  • Introducing Hooks adds a new way to write components, increasing the learning curve and potential for confusion.adr
  • The "Rules of Hooks" require unconditional calls, which can be unintuitive and complicate certain refactoring tasks.adr
  • Event handlers in Hooks may need recreation on each render, potentially reducing `PureComponent` and `React.memo` effectiveness.adr
  • Closures within Hooks can capture outdated props or state if dependencies are not correctly specified.adr
  • Hooks enable splitting a single component into smaller, more related functions.adr
  • Hooks allow reusing stateful logic between components without altering the component hierarchy.adr

The recorded why

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.

Source: text/0068-react-hooks.md