React Hooks - What's happening under the hood?

JavascriptReactjsReact Hooks

Javascript Problem Overview


I've been trying out React Hooks and they do seem to simplify things like storing state. However, they seem to do a lot of things by magic and I can't find a good article about how they actually work.

The first thing that seems to be magic is how calling a function like useState() causes a re-render of your functional component each time you call the setXXX method it returns?

How does something like useEffect() fake a componentDidMount when functional components don't even have the ability to run code on Mount/Unmount?

How does useContext() actually get access to the context and how does it even know which component is calling it?

And that doesn't even begin to cover all of the 3rd party hooks that are already springing up like useDataLoader which allows you to use the following...

const { data, error, loading, retry } = useDataLoader(getData, id)

How do data, error, loading and retry re-render your component when they change?

Sorry, lots of questions but I guess most of them can be summed up in one question, which is:

How does the function behind the hook actually get access to the functional/stateless component that is calling it so that it can remember things between re-renders and initiate a re-render with new data?

Javascript Solutions


Solution 1 - Javascript

React hook makes use of hidden state of a component, it's stored inside a fiber, a fiber is an entity that corresponds to component instance (in a broader sense, because functional components don't create instances as class components).

It's React renderer that gives a hook the access to respective context, state, etc. and incidentally, it's React renderer that calls component function. So it can associate component instance with hook functions that are called inside of component function.

This snippet explains how it works:

let currentlyRenderedCompInstance;
const compStates = new Map(); // maps component instances to their states
const compInstances = new Map(); // maps component functions to instances

function useState(initialState) {
  if (!compStates.has(currentlyRenderedCompInstance))
    compStates.set(currentlyRenderedCompInstance, initialState);

  return [
    compStates.get(currentlyRenderedCompInstance) // state
    val => compStates.set(currentlyRenderedCompInstance, val) // state setter
  ];
}

function render(comp, props) {
  const compInstanceToken = Symbol('Renderer token for ' + comp.name);

  if (!compInstances.has(comp))
    compInstances.set(comp, new Set());

  compInstances.get(comp).add(compInstanceToken);

  currentlyRenderedCompInstance = compInstanceToken;

  return { 
    instance: compInstanceToken,
    children: comp(props)
  };
}

Similarly to how useState can access currently rendered component instance token through currentlyRenderedCompInstance, other built-in hooks can do this as well and maintain state for this component instance.

Solution 2 - Javascript

Dan Abramov created a blog post just a couple days ago that covers this:

https://overreacted.io/how-does-setstate-know-what-to-do/

The second half specifically goes into details regarding hooks like useState.

For those interested in a deep dive into some of the implementation details, I have a related answer here: https://stackoverflow.com/questions/53974865/how-do-react-hooks-determine-the-component-that-they-are-for/53980190#53980190

Solution 3 - Javascript

I would recommend reading https://eliav2.github.io/how-react-hooks-work/

It includes detailed explanations about what is going on when using react hooks and demonstrate it with many interactive examples.

Note - the article does not explain in technical terms how React schedule calls for later phases, but rather demonstrates what are the rules that react uses to schedule calls for later phases.

Solution 4 - Javascript

The URL in another answer given by Eliav Louski is so far the best React explaination I have come across. This page should replace React's official tutorial as it removes all the magic from hooks and friends.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjonhobbsView Question on Stackoverflow
Solution 1 - JavascriptEstus FlaskView Answer on Stackoverflow
Solution 2 - JavascriptRyan CogswellView Answer on Stackoverflow
Solution 3 - JavascriptEliav LouskiView Answer on Stackoverflow
Solution 4 - JavascriptK PView Answer on Stackoverflow