- Published on
Rules of hooks
- Authors
- Name
- Nazarii Mural
- @NazariiMural
Prerequisites
In this short post about react hooks we are going to start with Conclusion 🎉🎉🎉
Conclusion
- What are hooks?
React hooks allow the usage of different React features inside functional components. - Where is components data stored?
All components data (next prev states
,props
...) are stored insideFiberNode
instance. - Why can't we use hooks conditionally?
React stores hooks execution order inside similar to the Linked List Data Structure where one hook has apointer
to thenext
one. And this data structure lives insideFiber tree
thought re-renders.
If the order of the hook execution is different between re-renders - nodes insideFiberNode
structure lose a pointer and point to a totally different thing and the whole structure simply can't work properly anymore.
What are hooks?
Hooks let you use different React features from your functional components, you can use:
- built-in hooks:
use
,useReducer
,useRef
,useContext
... - or you can build your own
Where is data stored?
Shortly: All components data (next, prev states
, props
...) are stored inside FiberNode.
Verbosely:
When we are building our React app, we are using components. Components are independent and reusable bits of code. Based on those components React is going to build virtual tree - this tree is called the fiber tree
.
Fiber Tree keeps track of all information about components
through re-render. Fiber Tree consists of nodes called - FiberNode
.
FiberNode keeps track of all information about single react component: state
, props
, owner
, and so on. For example, we are using several useState
hooks inside our component. When React computes Fiber Tree, React will write the default values of each individual useState
hook and the order they're called inside FiberNode
.
Let's take a look at the small component example:
function App() {
const [count, setCount] = useState<number>(0);
const [name, setName] = useState<string>("John");
return (
<div className="card">
<button onClick={() => setCount((c) => ++c)}>
Count is {count}
</button>
<hr />
<input value={name} onChange={(e) => setName(e.target.value)} />
</div>
);
}
export default App;
count="0"
and name="John"
; Now take a look at how this state is going to be represented inside FiberNode
As you can see order of the hooks execution is strictly the same as it is in our component above, and one useState has a pointer to another one FiberNode -> memoizedState -> next ->
. You may already guess where I'm going with it.So what happens after re-render? React is going to execute the app and pass the values that were kept in memory
inside the FiberNode
.
So the first state const [count, setCount] = useState<number>(0);
is going to be reading - into the first element of the linked list, and the second state const [name, setName] = useState<string>("John");
is going to be reading - into the second element of the linked list (into the property .next
of the first one).
What if at the next render, you add or remove a hook, in that case, you change the order of the execution of the hook and one or more of your hooks are going to point to the irrelevant data, to the data that is not related to that hook.
Why can't we use hooks conditionally?
React has to keep track of stuff for you in between renders.
Hooks rely on the order in which they're called. They are all interdependent in their linked lists. This is why you can't use them conditionally.
What does React Fiber solve?
When the re-render happens, React knows which elements should be rendered, and which information should be updated in the DOM, etc.
- Fiber can mark
state updates
in React with different levels of priority. - Fiber breaks the computation of the component tree into nodes, or
'units' of work
that it can commit at any time. - Fiber allows React to: pause, resume, or restart computation for various components.
Rules of hooks
🔴 Do not call Hooks inside conditions or loops.
🔴 Do not call Hooks after a conditional return
statement.
🔴 Do not call Hooks in event handlers.