HomeToolsAbout

Hooks

How to use it

A few rules apply to React hooks.

Following these rule will guarantee that hooks are called in the same order each time component renders.

You can only call hooks at the top level.

You can only call hooks at the top level.

  • You can’t call it inside loops or conditionals or nested functions.
  • You should be calling hooks at the top level of the React function, before any early returns.

If you want a conditional run of hook, place the condition logic inside the hook itself.

if(someCondition) { useEffect( ... ) } // wrong useEffect( () => { if(someCondition) { ... // correct } })

Only call hooks from React functions

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.

  • It should instead be a custom function.

State in Hooks

State in hooks do NOT share states. Each hook gets isolated states.

Custom Hooks

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 not to use Custom Hooks

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(); })

Caveat

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.

  • Only when the targeted event is invoked, the

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.

  • the idempotency requirement is broken and the app will behave in unexpected ways.
// 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.

AboutContact