A few rules apply to React hooks.
Following these rule will guarantee that hooks are called in the same order each time component renders.
hooks
at the top level
.You can only call hooks
at the top level
.
If you want a conditional run of hook, place the condition logic inside the hook itself.
if(someCondition) { useEffect( ... ) } // wrong useEffect( () => { if(someCondition) { ... // correct } })
Call hooks from custom hooks.
If you need to call a hook inside a loop, you have to extract a new component and move the state
into it and render it as a separate component instead.
If some function is reused in multiple places, but is not a component-related logic, it is NOT a hook in React.
State in hooks do NOT share states. Each hook gets isolated states.
A custom Hook is a JavaScript function whose name starts with use
and can call other Hooks.
useCustomHook() // React hook customReuse() // reused function
This convention is very important. Without it, we wouldn’t be able to automatically check for violations of rules of Hooks because we couldn’t tell if a certain function contains calls to Hooks inside of it.
When the shared logic is not a hook, don't encapsulate it and reuse it as a hook.
const useCustomHook = () => { useEffect( () => { // custom shared logic }) } // share the logic as a reusable function instead and call it explicitly in the components const customLogic = () => { // custom shared logic } // call the customLogic instead useEffect( () => { customLogic(); })
setState
in render
and Side Effect
What is bad practice is to call setState
explicitly in the render
method, because the render
method should be able to run multiple times without having any side effects
(Without affecting anything outside the render itself).
render(){ return ( // good, based on event <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> // bad, based on render {this.setState(() => ({}))} ); }
Referencing event call prevents setState
from immediately firing off.
setState
execution order is not guaranteed in Strict Mode
In React Strict Mode
, setState
can fire off before or after other non-state changing code within event trigger
callback function.
When the Strict Mode
is enabled and component is rendered twice in development mode, there is no guarantee that setState
is called in the correct order when other none state-changing code is mixed in.
// inside some event function (e) => { console.log("we are before setState") setState("we are in setState, doing something") console.log("we are after setState") }
In above function, on subsequent renders, there is no guarantee that the setState
will be executed second after the first log and before the third log.
// inside the same event function (e) => { setState(()=>{ console.log("we are inside setState, before action") console.log("we are in setState, doing something") console.log("we are after the action, still in setState") }) }
In contrast, above code will guarantee that the execution order of the setState
action will trigger in order as expected.
Lazy Computation
Every hook has an update queue
.
When you call the setState
function, React doesn't call the updater function immediately, but saves it inside the queue, and schedules a re-render.
There might be more updates after this one, to this hook, other hooks, or even hooks in other components in the tree.
React will calculate the new state
only when it actually needs it.