React Hooks is the new hotness in the React world. I’m writing steadily more and more of them and I thought it would be useful to have a cheatsheet to refer back to which encompasses the basic hooks as well as the intricacies of useEffect. Check out the official Hooks API Reference for more in-depth information.

Table of Contents

useEffect (for lifecycle methods)

useEffect, among other things, allows you to write your own side effects and trigger a re-render when needed.

But to make it simpler, useEffect also substitutes lifecycle methods. Let’s talk about them.

substitute for componentDidUpdate + componentDidMount

When does it run? On every render

What’s the catch? It’s not just a componentDidUpdate replacement, it also runs on mount. So it’s not 1-to-1

Important features? useEffect can take in a 2nd argument, you have to skip that argument. You can also return a function, we’ll cover that in the next section.

Code sandbox playground: Go play with it


import { useEffect } from 'react';

useEffect(() => {
  // whatever runs here will run on each re-render

substitute for componentDidMount + componentWillUnmount

When does it run? On component mount and unmount

What’s the catch? The syntax is very close to the previous use case. It threw me off several times but it makes sense once you read the docs. If the effect runs more than once, make sure you passed in the 2nd argument

Important features? This is an effect that runs only once. The mount logic goes in the body of the effect function, the unmount/cleanup logic goes into a function that you return from the effect.

Code sandbox playground: Go play with it


import { useEffect } from 'react';

useEffect(() => {
  // run mount logic here such as fetching some data

  return () => {
    // unmount logic goes here
}, []); // note the empty array

You can leave either the mount or unmount logic empty to work only off one of those lifecycle substitute. Meaning that:

  1. leave mount logic empty so that only unmount logic runs (substitute for just componentWillUnmount)
  2. return nothing so that only mount logic runs (substitute for just componentDidMount)

useEffect for side effects

useEffect‘s primary goal is to encompass any side effect you might want to use. A side effect is essentially something that you do within your component which affects the world at large. Whether that’s a network request, setting the document title, or what have you.

Run when necessary

When does it run? when the component re-renders, useEffect will check dependencies. If the dependency values changed, useEffect will run the effect

What’s the catch? React does a shallow comparison. If you use an object or an array that you mutate, React will think nothing changed.

Important features useEffect skips running the effect when things don’t change. You don’t actually have to use the dependency values in the effect. You can pass in a prop value as a dependency.

Code sandbox playground: Go play with it


import { useEffect } from 'react';

function SomeComponent(props) { 
    useEffect(() => {
      // logic runs only when dependency variables changed
    }, [arrOfDependency, values,]); // array of values to check if they've changed

Potential use cases

Since the hook is more difficult to explain, I’d like to offer a list of use cases

  1. run a side effect (like a fetch) when a prop changes to get new data
  2. run a resource-heavy calculation only when the calculation values change
  3. update the page (like document title) when a value updates


State is probably the reason why people switch from stateless (functional) components to class components. useState allows us to have stateful components without classes.

What does it return? Current state and a function that lets you set state

What’s the catch? The state setting function will replace the previous state with the new one rather than merging them as class state would have. You need to merge your objects yourself before setting the state.

Important features You can use as many useState hooks in your component as you want. Passing any value to useState will create the initial state. It’s also a convention to not call the variables state and setState but rather by contextual names (eg. user and setUser). useState accepts any value for state, it doesn’t have to be an object.

Code Sandbox playground: Check out the useState examples


import { useState } from 'react';

// setup
const defaultValue = { name: "Antonin" };
const [state, setState] = useState(defaultValue);

// scenario 1 usage
// resulting state only contains key `user` with value 'antjanus'
setState({ user: 'antjanus' }); 

// scenario 2 usage
// resulting state contains key `name` with value 'A. Januska'
setState({ name: 'A. Januska' }); 

// scenario 3 usage
// resulting state is a merger between `{ name: 'A. Januska' }` and `{ user: 'antjanus'}`
setState({ ...state, user: 'antjanus'}); 


useReducer is an alternative to useState and if you’ve used Redux in the past, this will look familiar.

What are the arguments? What does it return? useReducer takes in a reducer function and the initialState. It returns the current state and a dispatcher (sound familiar?)

How does it run? On state change, dispatch an object with a type and a data payload (read about flux standard action for more info). The reducer we passed into useReducer will receive the current state and the dispatched object. It returns the new state.

What’s the catch? It’s a more complicated workflow but it works just like you’d expect if you’ve used Redux.

Important features The reducer gets run on every dispatch. It gets access to the previous state. useReducer also includes a 3rd argument you can use to create the initial state

Code Sandbox playground: Check out the useReducer example


import { useReducer } from 'react';

function reducer(currentState, action) {
  switch(action.type) {
     // handle each action type and how it affects the current state here

function SomeComponent() {
  const [state, dispatch] = useReducer(reducer, initialState);

  dispatch({ type: 'ADD', payload: data }); // { type: 'ADD', payload: data } gets passed into the `reducer` as the `action` argument while `state` gets passed in as the `currentState` argument

Building Your Own Hooks

A quick note on building your own hooks. It’s as easy as using the existing hooks and composing them together inside of a function that starts with use. Here’s a quick example of a useUser hook.

What are the requirements? That the function starts with the keyword use. Eg. useUser or useSomethingElse.

Important features: you can call any hooks within your custom hook and it works as expected.

Code Sandbox playground: Check out the custom hooks example


import { useEffect } from 'react';

function useUser(userId) {
  let [user, setUser] = useState(null);

  useEffect(() => {
        .then(data => data.toJSON())
        .then(data => setUser(data));
  }, [userId]);

  return user;

function SomeComponent(props) {
  const user = useUser(;

What about the rest?

There are other hooks you can use such as useMemo, useCallback and so on. I would say that those are more advanced hooks and if you understand the basic hooks, go ahead and check out the official docs.

I also understand there are some advanced usage examples for many of these (like passing useReducer’s dispatch down several levels).

If you find something incorrect or some extra information useful that isn’t included, let me know! And I’ll include it!

Did you find the cheatsheet useful? Buy me a coffee so I can keep doing this and produce more content! 🙂 You can also follow me on Twitter