bugl
bugl
HomeLearnPatternsPathsSearch
HomeLearnPatternsPathsSearch

Loading lesson path

Learn/React/Hooks and State Management
React•Hooks and State Management

React useEffect Hooks

Flash cards

Review the key moves

1/4
Core idea

What is the main idea behind React useEffect Hooks?

Lesson checks

Practice each idea before moving on

Short Mimo-style checks built from this lesson's code, terms, and sequence.

1Quick choice

Which statement best captures the main point of this lesson?

2Fill blank

Complete the missing token from the example code.

___ { useState, useEffect } from 'react';
3Order

Put the learning moves in the order that makes the concept easiest to apply.

Some examples of side effects are: fetching data, directly updating the DOM, and timers.
The useEffect Hook allows you to perform side effects in your components.
React useEffect Hooks

The useEffect Hook allows you to perform side effects in your components.

Some examples of side effects are: fetching data, directly updating the DOM, and timers.

useEffect accepts two arguments. The second argument is optional.

useEffect(<function>, <dependency>)

Let's use a timer as an example.

Example

Use setTimeout() to count 1 second after initial render:

import { useState, useEffect } from 'react';
import { createRoot } from 'react-dom/client';
function Timer() {
 const [count, setCount] = useState(0);
 useEffect(() => {
 setTimeout(() => {
 setCount((count) => count + 1);
 }, 1000);
 });
 return <h1>I've rendered {count} times!</h1>; }
 createRoot(document.getElementById('root')).render( <Timer /> );

But wait!! It keeps counting even though it should only count once!

useEffect runs on every render. That means that when the count changes, a render happens, which then triggers another effect.

This is not what we want. There are several ways to control when side effects run.

We should always include the second parameter which accepts an array. We can optionally pass dependencies to useEffect in this array.

Example

  1. No dependency passed:
useEffect(() => {
 //Runs on every render
});

Example

  1. An empty array:
useEffect(() => {
 //Runs only on the first render
}, []);

Example

  1. Props or state values:
useEffect(() => {
 //Runs on the first render //And any time any dependency value changes
}, [prop, state]);

So, to fix this issue, let's only run this effect on the initial render.

Example

Only run the effect on the initial render:

import { useState, useEffect } from 'react';
import { createRoot } from 'react-dom/client';
function Timer() {
 const [count, setCount] = useState(0);
 useEffect(() => {
 setTimeout(() => {
 setCount((count) => count + 1);
 }, 1000);
 }, []); // <- add empty brackets here
 return <h1>I've rendered {count} times!</h1>; }
 createRoot(document.getElementById('root')).render( <Timer /> );

Example

Here is an example of a useEffect Hook that is dependent on a variable. If the count variable updates, the effect will run again:

import { useState, useEffect } from 'react';
import { createRoot } from 'react-dom/client';
function Counter() {
 const [count, setCount] = useState(0);
 const [calculation, setCalculation] = useState(0);
 useEffect(() => {
 setCalculation(() => count * 2);
 }, [count]); // <- add the count variable here
 return ( <> <p>Count: {count}</p> <button onClick={() => setCount((c) => c + 1)}>+</button> <p>Calculation: {calculation}</p> </> );
}
createRoot(document.getElementById('root')).render( <Counter /> );

If there are multiple dependencies, they should be included in the useEffect dependency array.

Effect Cleanup

Some effects require cleanup to reduce memory leaks.

Timeouts, subscriptions, event listeners, and other effects that are no longer needed should be disposed.

We do this by including a return function at the end of the useEffect Hook.

Example

Clean up the timer at the end of the useEffect Hook:

import { useState, useEffect } from 'react';
import { createRoot } from 'react-dom/client';
function Timer() {
 const [count, setCount] = useState(0);
 useEffect(() => {
 let timer = setTimeout(() => {
 setCount((count) => count + 1);
 }, 1000);
 return () => clearTimeout(timer)
 }, []);
 return <h1>I've rendered {count} times!</h1>; }
 createRoot(document.getElementById('root')).render( <Timer /> );

Note

To clear the timer, we had to name it.

Previous

React useState Hook

Next

React useContext Hook