81

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?

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
jonhobbs
  • 26,684
  • 35
  • 115
  • 170

3 Answers3

70

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.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • So this 'fiber' object is the real instance of the component. Like, behind the scenes, it's sortof a class component, where This is inaccessible, and the only code you get to write is the render method. Seems pretty crippled. I'm always attaching stuff to the This object, like large objects that control other stuff, or pre-calculated or cached stuff that I want to use later. – OsamaBinLogin Aug 16 '23 at 07:52
15

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: How do react hooks determine the component that they are for?

Ryan Cogswell
  • 75,046
  • 9
  • 218
  • 198
3

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.

Eliav Louski
  • 3,593
  • 2
  • 28
  • 52