useEffect

A Hook that lets you perform side effects in functional components.

Data fetching, setting up a subscription, manually changing the DOM, and the use of time functions such as setTimeout() in React components are all examples of side effects (or just “effects”).

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount(), componentDidUpdate(), and componentWillUnmount() combined.

There are two common kinds of side effects in React components: those that don’t require cleanup, and those that do.

Effects Without Cleanup

Sometimes, we want to run some additional code after React has updated the DOM.

Network requests, manual DOM mutations, and logging are common examples of effects that don’t require a cleanup. We say that because we can run them and immediately forget about them.

  • Placing useEffect inside the component lets us access the count state variable (or any props) right from the effect. We don’t need a special API to read it — it’s already in the function scope.

  • useEffect runs both after the first render and after every update.

import React, { useState, useEffect } from 'react';
function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => { document.title = `You clicked ${count} times`; });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Effects With Cleanup

Closing a socket, clearing timers, and setting up a subscription to some external data source are some common examples that do require a cleanup.

It is important to clean up so that we don’t introduce a memory leak!

  • If your effect returns a function, React will run it when it is time to clean up. This lets us keep the logic for adding and removing subscriptions close to each other. They’re part of the same effect!

  • React performs the cleanup when the component unmounts. However, effects run for every render and not just once. This is why React also cleans up effects from the previous render before running the effects next time.

import React, { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

Unlike componentDidMount() or componentDidUpdate(), effects scheduled with useEffect don’t block the browser from updating the screen. This makes your app feel more responsive.

Skipping effects

By default, the useEffect Hook runs after the first render as well as after each update. However, you might need to skip applying an effect in situations like when certain values haven’t changed since the last re-render.

You can easily skip applying effects by passing an array as a second argument to the useEffect Hook. As arguments, you can pass props or state values. When an argument is passed, the useEffect Hook will be executed after the initial render and only when the argument values change.

Consider the following example, in which the effect is only invoked if the variable count is updated.

useEffect(() => {
  console.log(count);
}, [count]);

If you want to run and clean up the effect only once, you can pass an empty array ([]) as the second argument.

useEffect Hook accepts a callback function that is invoked whenever a render occurs.

Last updated