Register to get access to free programming courses with interactive exercises

useEffect Hook JS: React Hooks

To carry out side effects, for example, working directly with the DOM in React, we use the built-in useEffect(). It replaces three life cycle callbacks:

  • componentDidMount()
  • componentDidUpdate()
  • componentWillUnmount()

If you forgot or didn't know how they work, you can read more about them in the official documentation.

Let's start with a simple example:

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

const Example = () => {
  const [count, setCount] = useState(0);

  // Works like componentDidMount and componentDidUpdate combined
  // Starts after rendering the component
  // Called after each click on the button
  useEffect(() => {
    // The state is accessible internally, as the scope is normal
    alert(`Clicks ${count}`);
  });

  // With classes, we'd do this
  // Note the duplication
  // componentDidMount() {
  //   alert(`Clicks: ${count}`);
  // }
  // componentDidUpdate() {
  //   alert(`Clicks: ${count}`);
  // }

  return (
    <div>
      <p>You clicked {count} time(s)</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
};

Below is an example in which the background changes with each click:

See the Pen js_react_hooks_use_effect-1 by Hexlet (@hexlet) on CodePen.

The callback passed to useEffect() is processed after the component's first rendering and after each update. In other words, we combined the componentDidUpdate() and componentDidMount() methods for convenience.

The practice using React has shown that effects occur after each render, regardless of whether this is the first or subsequent rendering. We reduced the amount of duplication in our code as a bonus.

Let us observe some typical side effects found in the front end:

  • Data extraction
  • Working with the BOM API (Browser Object Model), for example, Local Storage
  • Direct DOM modification, this also includes libraries that are incompatible with React

Sometimes we can skip the action of the useEffect() hook. It can be helpful for optimization purposes or cases when we use the effect only under certain conditions.

To do this, we should track an array of values between renderings passed to the hook as the second argument. We trigger the callback if we change at least one value from this array.

If all values remain the same, we skip it:

useEffect(() => {
  alert(`Clicks ${count}`);
}, [count]);

// Equivalent
componentDidUpdate(prevProps, prevState) {
  if (prevState.count !== this.state.count) {
    alert(`Clicks ${count}`);
  }
}

In other words, we trigger the callback only when the count changes.

In the same way, you can pass any set of variables to associate them with the effect change. The effect will work when at least one variable in the passed array has changed. Otherwise, React will skip it.

How can we run useEffect() only when the first render occurs (immediately after mounting)?

To do so, you need to pass an empty array:

// Replaces componentDidMount

useEffect(() => {
  alert(`Clicks ${count}`);
}, []);

This solution isn't the most obvious, but technically, it is not a specific case. Someday you will get used to it.

Resetting the effect

Sometimes we need to reset. For instance, we should clean the effect up when it ceases to be relevant after changing the props.

To do this, you can return the function from useEffect() to move the cleanup inside:

// Let's assume that this effect depends on the userId prop
useEffect(() => {
  const id = setTimeout(/* some code with userId */);

  return () => clearTimeout(id);
}, [userId]);

Changing the userId will reset the current timer and install a new one. This code would require as many as four life cycle callbacks in classes.

We can connect the cleanup to an empty array with a second parameter to simulate componentWillUnmount():

useEffect(() => {
  return () => {
    // This logic executes only when the component is unmounted
  };
}, []);

Recommended materials

  1. Using the Effect Hook
  2. Why Effects Run on Each Update

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.bookmate">Bookmate</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.healthsamurai">Healthsamurai</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.dualboot">Dualboot</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.abbyy">Abbyy</span>
Suggested learning programs
profession
Development of front-end components for web applications
10 months
from scratch
Start at any time

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.