The Guild
Published in

The Guild

Under the hood of React’s hooks system

Looking at the implementation and getting to know it inside out

A rough schematic representation of React’s hooks system

The dispatcher

The dispatcher is the shared object that contains the hook functions. It will be dynamically allocated or cleaned up based on the rendering phase of ReactDOM, and it will ensure that the user doesn’t access hooks outside a React component (see implementation).

Dispatcher implementation in a nutshell.

The hooks queue

Behind the scenes, hooks are represented as nodes which are linked together in their calling order. They’re represented like so because hooks are not simply created and then left alone. They have a mechanism which allows them to be what they are. A hook has several properties which I would like you to bare in mind before diving into its implementation:

  • Its state can be updated on the fly.
  • React would remember the hook’s state in future renders.
  • React would provide you with the right state based on the calling order.
  • React would know which fiber does this hook belong to.
React state — the old way.
React state — the new way.
  • baseUpdate - The most recent dispatched action that created the baseState.
  • queue - A queue of dispatched actions, waiting to go through the reducer.
Hooks queue implementation in a nutshell.
An external read of a component’s memoized state.

State hooks

You would be surprised to know, but behind the scenes the useState hook uses useReducer and it simply provides it with a pre-defined reducer handler (see implementation). This means that the results returned by useState are actually a reducer state, and an action dispatcher. I would like you to take a look at the reducer handler that the state hook uses:

State hook reducer, aka basic state reducer.
Returning a new state relatively to the old one.

Effect hooks

Effect hooks behave slightly differently and has an additional layer of logic that I would like to explain. Again, there are things I would like you to bare in mind regards the properties of the effect hooks before I dive into the implementation:

  • If given so, they’ll be destroyed right before the next painting.
  • They’re called in their definition order.
  • Perform all the host insertions, updates, deletions and ref unmounts (see implementation).
  • Perform all life-cycles and ref callbacks. Life-cycles happen as a separate pass so that all placements, updates, and deletions in the entire tree have already been invoked. This pass also triggers any renderer-specific initial effects (see implementation).
  • Effects which were scheduled by the useEffect() hook - which are also known as “passive effects” based on the implementation (maybe we should start using this term within the React community?!).
  • create - The callback that should be ran after painting.
  • destroy - The callback returned from create() that should be ran before the initial render.
  • inputs - A set of values that will determine whether the effect should be destroyed and recreated.
  • next - A reference to the next effect which was defined in the function Component.
Supported hook effect types by React.
An example which shows how to use React’s binary design pattern.
  • Mutation effect — UnmountSnapshot | MountMutation.
  • Layout effect — UnmountMutation | MountLayout.
A real snapshot from React’s implementation.
Example of effects injection.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store