DEV Community

Cover image for The Definitive React Hooks Cheatsheet
Antonin J. (they/them)
Antonin J. (they/them)

Posted on • Edited on • Originally published at antjanus.com

The Definitive React Hooks Cheatsheet

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

Syntax:

import { useEffect } from 'react';

useEffect(() => {
  // whatever runs here will run on each re-render
});
Enter fullscreen mode Exit fullscreen mode

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

Syntax:

import { useEffect } from 'react';

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

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

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

Syntax:

import { useEffect } from 'react';

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

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

useState

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

Syntax:

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'}); 
Enter fullscreen mode Exit fullscreen mode

useReducer

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

Syntax

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
}
Enter fullscreen mode Exit fullscreen mode

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

Syntax:

import { useEffect } from 'react';

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

  useEffect(() => {
    fetch(`/api/user/${userId}`)
        .then(data => data.toJSON())
        .then(data => setUser(data));
  }, [userId]);

  return user;
}

function SomeComponent(props) {
  const user = useUser(props.id);
}
Enter fullscreen mode Exit fullscreen mode

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

Top comments (14)

Collapse
 
learnwithparam profile image
Paramanantham Harrison

Thanks man. Are you sure about naming with ‘use’?
I don’t think it’s mandatory, you can create any named function as hooks. Probably this might be the recommended way same as how HOC are made with ‘with’ prefix

Collapse
 
camilomejia profile image
Camilo Mejía

The React team provide an ESLint plugin that prevents incorrect usage of hooks, but you must name them with use.

reactjs.org/docs/hooks-faq.html#wh...

Collapse
 
learnwithparam profile image
Paramanantham Harrison

Yeah I got it, thanks for the link

Collapse
 
claudiobernasconi profile image
Claudio Bernasconi

It's a suggestion by the React team - a best practice to make the intent clear.

Collapse
 
antjanus profile image
Antonin J. (they/them)

Interesting. I guess I haven't tested it but it's straight from their docs:

A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks

Collapse
 
juliang profile image
Julian Garamendy

Hi Antonin, Thanks for writing this. I think it's very useful.

I have one comment regarding your useUser hook. I think it's important to "cancel" the request before the component unmounts to avoid memory leaks.
I wrote about it a few days ago. You might want to have a look:
dev.to/juliang/cancelling-a-promis...

Cheers!

Collapse
 
guico33 profile image
guico33

In this case there's no memory leak though.
It's simply a warning as updating the state will effectively do nothing after the component has been unmounted.

Collapse
 
juliang profile image
Julian Garamendy

Ah. I see your point. I suppose the dangling reference to the component gets garbage-collected after the promise resolves and state is updated?

Collapse
 
bbarbour profile image
Brian Barbour

Is it possible to use a custom hook in place of something like a render prop or a higher order component?

Collapse
 
kayis profile image
K • Edited

Yes, that was one of the use-cases they had in mind when creating hooks.

Collapse
 
bbarbour profile image
Brian Barbour

Awesome. I now I need to practice and figure out how to do that.

Collapse
 
httpjunkie profile image
Eric Bishard

Nice article, I like the useReducer code sandbox example, pretty straight forward. I follow a similar template in my "Guide to Learning React Hooks article", you should check it out.

Collapse
 
rohovdmytro profile image
Rohov Dmytro • Edited

Thanks for an article.

Another great place to wrap a head around hooks is Dan's blog.

Collapse
 
antjanus profile image
Antonin J. (they/them)

Dan's blog is awesome.