Hooks

The new React docs are great material for understanding hooks and how to use them in your code. The flow diagram below can also help build your mental model around when certain hook actions are "running" during the component lifecycle.

hook flow chart

useState

Common questions:

Tips:

  • If the initial value for your state is computationally expensive, consider lazy state initialization to ensure it only runs once per component mount
  • If you are updating state values (with setState()) many times throughout your component, you'd probably benefit by switching to the reducer pattern or even defining a custom hook.
  • Read the Common Pitfalls of useState
  • Store as little "state" as possible, derive as much as you can on the fly (e.g. if your form has a "first name" and "last name" fields but you also need to display the full name together, just concatenate the two values together, don't try to store this value in it's own "fullName" state variable)
  • Don't try to update one property in an object or one item in an array, instead you should replace the entire object/array with what the new state value should be. If you need an object to persist between renders but that shouldn't cause re-renders when you change that object, you probably need a ref (useRef)

useEffect / useLayoutEffect

Effects are code that run last during the rendering cycle. You may hear that effects actually run AFTER rendering is complete. What matters is that you know effect code runs last, whether you actually consider it part of the rendering phase or it's own step that happens AFTER rendering phase probably doesn't matter.

You might be using effects wrong if:

  • You have code in an effect that "resets" all local component state when a prop changes for that component (read You Might Not Need an Effect)
  • Effects are NOT "subscriptions" - try not to think of them as a way to "opt in" or listen to changes to specific variables. Thinking this way can lead to pointless re-renders and therefore laggard performance in your apps
  • Related to the above point, if you are updating state with setState() inside of your effect, you might be doing something wrong (not always, but we find this more true than not). Since effects run last in the render phase, updating state from there will immediately cause your component to re-render

Tips:

  • Read Dan Abramov's Complete Guide to useEffect (and then, when you think you understand effects, read it again)
  • When effects run
    • useEffect(() ⇒ {}) - will run after every render of a component
    • useEffect(() ⇒ {}, []) - will run only after the first render of a component
    • useEffect(() ⇒ {}, [deps]) - will run after renders, but only when deps change

Advanced Hooks

useRef - this is very similar to useState, except updates to the state value (like setState()) do NOT trigger re-renders

useMemo, useCallback - memoize values and functions that don't need to be re-declared every single render-cycle

useReducer - we especially recommend this if there are many calls to update state from your component. When to reach for useReducer over useState is very nuanced, but we tend to relate it to how many values are kept in local state and how often they are updating. As the number of values and number of updates to those values in your component increase, the more likely you should consider useReducer instead of plain useState.

Ready to Use Hooks

You can also copy+paste hooks from the websites below into your own projects. If you prefer to keep npm dependencies as light as possible, you could copy over only the ones you need.