React Grimoire
  • ⁉️Introduction
  • 🧑‍🎓🧑🎓 React Fundamentals
    • The Basic javascript "Hello world"
    • Basic view on React core API's
    • JSX
    • React Props and styling
    • Components
    • Handling Events With React
    • Form
    • Array and Lists
    • Class Component State
    • Class Component Life Cycle
    • PropTypes
  • 🪝React Hooks
    • Intro to hooks
    • useState
    • useEffect
    • useRef
    • useContext
    • useMemo
    • useCallback
    • useReducer
    • useLayoutEffect
    • useImperativeHandle
    • Hook flow
    • Custom hooks
      • useDebugValue
    • React 18 hooks
  • 📓React Guidelines
    • React Components Composition Guidelines
    • React hooks guidelines
    • The use of Memoization
    • Lifting State Up
  • 🔭Concepts
    • Advanced Patterns
      • Compound Components Pattern
      • Control Props Pattern
      • Props Getters Pattern
      • Custom hook pattern
      • Context Module
      • State Reducer
    • React Under the hood
      • 🏁What is "Rendering"?
      • 🏁React Lifecycle
      • 🏁Reconciliation & Virtual DOM in React
      • 🏁Fiber
    • ⏰Concepts to always have in mind
  • 🧩React ecosystem
    • Forms Tools
      • React Hook Form VS Formik
    • TypeScript
      • 🏁Conditional React props with TypeScript
    • 🏁Build tool choice for MVP projects
    • A CSS methodology comparison
      • 🏁Post CSS processor :Sass
      • 🏁CSS in js :Styled-components
      • 🏁Utility Classes: Tailwind
  • ⁉️Testing
    • In Progress
  • 🎭Performance
    • in Progress
  • 🚀Deployment
    • In Progress
  • 🖼️Design system
    • 🏁What's a design system anyway ?​?
  • 🔗Us-full links
    • Typescript and React basic tutorial
    • React-philosophies
    • React new doc
Powered by GitBook
On this page
  • What are effects
  • React side Effect
  • Empty dependency array
  • Triggering Effect
  • Skipping effects
  • Multiple effects
  • Cleaning up an effect
  • What is the useEffect cleanup function?
  • Why is the useEffect cleanup function useful?
  • When should we use the useEffect cleanup?
  • Fetch Data from an API
  • Create the asynchronous function
  • References and articles :

Was this helpful?

Edit on GitHub
  1. React Hooks

useEffect

PrevioususeStateNextuseRef

Last updated 3 years ago

Was this helpful?

React.useEffect is an in-built hook that lets you run custom code after React renders (and re-renders) your component to the DOM. It accepts a callback function that React will call after the DOM has been rendered, but first, let's define an effect.

What are effects

The term "Side Effect" does not refer to a specific reaction. It is a broad concept referring to the behaviors of functions. If a function attempts to modify anything outside of its body, it is said to have a side effect. It is a side effect, for example, if it modifies a global variable. It is also a side effect if it makes a network call.

Side effects are defined as anything that has an effect on something that is not within the scope of the current function being executed.

React side Effect

However, there are times when we need our components to interact with APIs that are not part of the data-flow process. A side effect is an action that has an impact on the outside world in some way. The following are common side effects:

  • handling subscriptions with event listeners

  • dealing with manual DOM changes.

  • Logging messages to the console or other service

  • Setting or getting values in local storage

  • Fetching data or subscribing and unsubscribing to services

The basic signature of useEffect is as follows:

Let's analyse this example

import * as React from "react";

const BasicEffect = () => {
  const [counter, setCounter] = React.useState(0);
  const handleClick = () => setCounter((prev) => prev + 1);

  React.useEffect(() => {
    handleClick();
  });

  return (
    <div>
      <span> {`Counter is ${counter}`} </span>
    </div>
  );
};

As we can see, useEffect will force the component to redraw because it is always invoked after each redraw, so when the counter is updated, useEffect will invoke handleClick, and we will be in an infinite loop.

Empty dependency array

import * as React from "react";

const BasicEffect = () => {
  const [counter, setCounter] = React.useState(0);
  const handleClick = () => setCounter((prev) => prev + 1);

  React.useEffect(() => {
    handleClick();
  },[]);

  return (
    <div>
      <span> {`Counter is ${counter}`} </span>
    </div>
  );
};

useEffect is passed an empty array, []. Hence, the effect function will be called only on mount

Triggering Effect

Let's take this example

import * as React from "react";

const BasicEffect = () => {
  const [counter, setCounter] = React.useState(0);
  const handleClick = () => setCounter((prev) => prev + 1);

  React.useEffect(() => {
    handleClick();
  },[count]);

  return (
    <div>
      <span> {`Counter is ${counter}`} </span>
    </div>
  );
};

We still have an infinite loop , but why is that

The dependency array basically tells the hook to "only trigger when the dependency array changes". In the above example, it means "run the callback every time the counter variable changes".

If you have multiple elements in a dependency array, the hook will trigger if any element of the dependency array changes.

Skipping effects

const ArrayDepMount = () => {
  const [randomNumber, setRandomNumber] = useState(0)
  const [effectLogs, setEffectLogs] = useState([])

  useEffect(
    () => {
      setEffectLogs(prevEffectLogs => [...prevEffectLogs, 'effect fn has been invoked'])
    },
    [randomNumber]
  )

  return (
    <div>
      <h1>{randomNumber}</h1>
      <button
        onClick={() => {
          setRandomNumber(Math.random())
        }}
      >
        Generate random number!
      </button>
      <div>
        {effectLogs.map((effect, index) => (
          <div key={index}>{'🍔'.repeat(index) + effect}</div>
        ))}
      </div>
    </div>
  )
}

We can see that the effect is dependent on the randomNumber state and will only be triggered if the randomNumber value has changed.

If your effect is dependent on a state or prop value in scope, make sure to pass it as an array dependency to avoid accessing stale values within the callback. If the values referenced change over time and are used in the callback, include them in the array dependency.

The importance of the dependency array

If no dependency array is provided, every scheduled useEffect is executed. This means that after each render cycle, each effect defined in the corresponding component is executed in the order specified in the source code.

As a result, the order of your effect definitions is important. In our case, whenever one of the state variables changes, our single useEffect statement is executed. In the source code, sitioning is used.

As array entries, you provide. React only executes the useEffect statement in these cases if at least one of the provided dependencies has changed since the previous run. In other words, the dependency array makes the execution conditional on certain conditions.

Most of the time, this is what we want; we usually want to execute side effects when certain conditions are met, such as when data changes, a prop changes, or the user first sees our component.

Multiple effects

Multiple useEffect calls can happen within a functional component, as shown below:

const MultipleEffects = () => {
  // ⏬ 
  useEffect(() => {
    const clicked = () => console.log('window clicked')
    window.addEventListener('click', clicked)

    return () => {
      window.removeEventListener('click', clicked)
    }
  }, [])

  // ⏬  another useEffect hook 
  useEffect(() => {
    console.log("another useEffect call");
  })

  return <div>
    Check your console logs
  </div>
}

Note that useEffect calls can be skipped, not invoked on every render. This is done by passing a second array argument to the effect function.

Cleaning up an effect

The application of React By cleaning up effects, the effect cleanup function protects applications from undesirable behaviors such as memory leaks. We can improve the performance of our application by doing so.

What is the useEffect cleanup function?

The useEffect cleanup function, as the name implies, allows us to clean up our code before our component unmounts. When our code runs and reruns for each render, useEffect uses the cleanup function to clean up after itself.

The useEffect Hook is designed in such a way that we can return a function from within it, and it is within this return function that the cleanup occurs. The cleanup function prevents memory leaks and eliminates some unwanted and unnecessary behaviors.

Note that you don’t update the state inside the return function either:

Why is the useEffect cleanup function useful?

As previously stated, the useEffect cleanup function assists developers in cleaning up effects that prevent unwanted behaviors and improve application performance.

It is important to note, however, that the useEffect cleanup function runs not only when our component wants to unmount, but also right before the execution of the next scheduled effect.

In fact, the next scheduled effect is usually based on the dependency array after our effect has completed.

As a result, whenever our effect is dependent on our prop or whenever we set up something that persists, we have a reason to invoke the cleanup function.

Consider the following scenario: suppose we receive a fetch of a specific user via a user's id and, before the fetch is completed, we change our mind and attempt to obtain another user.

While the previous fetch request is still in progress, the prop, or in this case, the id, updates. To avoid exposing our application to a memory leak, we must abort the fetch using the cleanup function.

When should we use the useEffect cleanup?

Let’s say we have a React component that fetches and renders data. If our component unmounts before our promise resolves, useEffect will try to update the state (on an unmounted component) and send an error that looks like this:

To fix this error, we use the cleanup function to resolve it.

"React performs the cleanup when the component unmounts" according to the official documentation. However, effects are applied to each render, not just the first. This is why React also cleans up effects from previous renders before running them again."

The cleanup is commonly used to cancel all subscriptions made and cancel fetch requests.

Fetch Data from an API

Create the asynchronous function

const fetchData = async (url) => {
    try {
        const response = await fetch(url);
        const json = await response.json();
        console.log(json);
		} catch (error) {
        console.log("error", error);
		}
};

Put the fetchData function above in the useEffect hook and call it, like so:

useEffect(() => {
    // advice free ap
    const url = "https://api.adviceslip.com/advice";

    const fetchData = async () => {
      try {
        const response = await fetch(url);
        const json = await response.json();
        console.log(json);
      } catch (error) {
        console.log("error", error);
      }
    };

    fetchData();
}, []);

Then, instead of printing the advice in the console, we'll save it in the advice state.

const [advice, setAdvice] = useState("")
setAdvice(json.slip.advice)

References and articles :

is a hook to let you invoke side effects from within functional components,

It is also possible to add an empty dependency array. In this case, effects are only executed once; it is similar to the lifecycle method. (similar by not exactly the same)

The React team recommends you use the package. It warns when dependencies are specified incorrectly and suggests a fix.

Then, let's create an to fetch our data. An asynchronous function is a function that needs to wait after the is resolved before continuing. In our case, the function will need to wait after the data is fetched (our promise) before continuing.

The function we just created is wrapped in a so that the function catches the errors and prints them in the console. This helps debug and prevents the app to crash unexpectedly.

Inside of the try, we are using the built-in to get the advice from the Advice Slip JSON API. We put the keyword just in front of it to tell the function to wait for the fetch task to be done before running the next line of code.

Once we get a response, we are parsing it using the , meaning that we are transforming the response into JSON data that we can easily read. Then, we are printing the JSON data in the console.

🪝
useEffect
componentDidMount()
eslint-plugin-react-hooks
asynchronous function
promise
try...catch statement
fetch API from JavaScript
await
.json() function
A Complete Guide to useEffect
A Visual Guide to useEffect
Side effect (computer science)Wikipedia
A Visual Guide to useEffect - Cleanups
The last guide to the useEffect Hook you'll ever need - LogRocket BlogLogRocket Blog
useEffect(), Http Requests & Abortingacademind_real
Logo
How To Call Web APIs with the useEffect Hook in React | DigitalOcean
How to use async functions in useEffect (with examples) - DevtriumDevtrium - Tutorials on React and Javascript, updated weekly!
5 Tips to Help You Avoid React Hooks Pitfallskentcdodds
Myths about useEffectMyths about useEffect
Logo
Logo
Logo
Logo
Logo
Warning Error
Logo
Logo
Logo
Logo