Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Hooks - What's happening under the hood?

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?

like image 715
jonhobbs Avatar asked Dec 11 '18 18:12

jonhobbs


People also ask

How do React Hooks actually work?

Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks don't work inside classes — they let you use React without classes. (We don't recommend rewriting your existing components overnight but you can start using Hooks in the new ones if you'd like.)

Which React hook causes side effects?

If you're familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount , componentDidUpdate , and componentWillUnmount combined. There are two common kinds of side effects in React components: those that don't require cleanup, and those that do.

When should you not use a hook on a React?

1. Changing the Hooks Invocation Order. Hooks should not be called within loops, conditions, or nested functions since conditionally executed Hooks can cause unexpected bugs. Avoiding such situations ensures that Hooks are called in the correct order each time the component renders.


1 Answers

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.

like image 132
Estus Flask Avatar answered Sep 20 '22 14:09

Estus Flask