Translation: The rolling curtain is still

Original address: dmitripavlutin.com/react-useef…

I was impressed by the rich functionality of React Hooks – you can do a lot with very little code.

However, the brevity of hooks comes at a cost – getting started is relatively difficult. Especially useEffect()- this hook is used to handle side effects in the React component.

In this article, you will learn how and when to use the useEffect() hook

1. UseEffect () is used to handle side effects

The React functional component evaluates the output with props and state. If the goal of a functional component is not to output a value, these calculations are collectively referred to as side effects.

Side effects include network requests, direct DOM manipulation, and the use of timer functions (such as setTimeout()).

The logic of component rendering and side effects is separate. Performing side effects directly within a component is a mistake because the component’s original goal is to compute the output.

The number of times a component renders is something you can’t control – if React needs to render a component, you can’t stop it.

function Greet({ name }) {
    const message = `Hello, ${name}! `; // Calculate the output
    // Bad!
    document.title = `Greetings to ${name}`; // Side effects!
    return <div>{message}</div>;       // Calculate the output
}
Copy the code

So how do you decouple component rendering from side effects? This is where useEffect() comes in – a hook independent of the side effects of rendering runs.

import { useEffect } from 'react';
function Greet({ name }) {
  const message = `Hello, ${name}! `;   // Calculate the output
  useEffect(() = > {
    // Good!
    document.title = `Greetings to ${name}`; // Side effects!
  }, [name]);
  return <div>{message}</div>;         // Calculate the output
}
Copy the code

UseEffect () takes two arguments:

useEffect(callback, [dependencies])
Copy the code
  • callbackIs a function that contains side effect logic after each DOM updatecallbackWill perform
  • dependenciesIs an optional dependency array.useEffect()It is executed only when dependencies change between renderscallback

Put the side effect logic in the callback (callbackFunction, and then use the dependent argument (dependencies argument) control when side effects occur. That isuseEffect()The only goal.

For example, you can see useEffect() in action in the previous code snippet:

useEffect(() = > {
    document.title = `Greetings to ${name}`;
}, [name]);
Copy the code

The document.title change is a side effect because it does not directly evaluate the component’s output. That is why the update logic for the document title is put in fire and supplied with useEffect().

In addition, there is no need to update the Greet document title every time the Greet component renders, but only when the name changes – hence the useEffect(callback, [name]) dependency.

2. Rely on parameters

The useEffect(callback, Dependencies) dependency parameter allows you to control when a side effect executes. According to different dependent parameters, there are the following three situations:

  1. No incoming: side effects inEvery timeIt will run after rendering
import { useEffect } from 'react';
function MyComponent() {
  useEffect(() = > {
    // Runs after EVERY rendering
  });  
}
Copy the code
  1. Passing an empty array[]: Side effects are only performed after the initial renderingAt a time
import { useEffect } from 'react';
function MyComponent() {
  useEffect(() = > {
    // Runs ONCE after initial rendering} []); }Copy the code
  1. The incomingpropsorstate: Any change in dependency parameters can cause side effects
import { useEffect, useState } from 'react';
function MyComponent({ prop }) {
  const [state, setState] = useState(' ');
  useEffect(() = > {
    // Runs ONCE after initial rendering
    // and after every rendering ONLY IF `prop` or `state` changes
  }, [prop, state]);
}
Copy the code

Let’s expand on the second and third cases, because they are very common in practice.

3. Component life cycle

3.1 Component Mounting

Using an empty array as a dependency, the side effect is performed only once after the component is mounted:

import { useEffect } from 'react';
function Greet({ name }) {
  const message = `Hello, ${name}! `;
  useEffect(() = > {
    // Runs once, after mounting
    document.title = 'Greetings page'; } []);return <div>{message}</div>;
}
Copy the code

useEffect(… The dependency parameter in, []) is an empty array, in which case the callback in useEffect() is executed only once after the initial mount of the component.

Although a change in the name attribute causes the component to be re-rendered, the side effect is only performed once after the first rendering:

// First render
<Greet name="Eric" />   // Side-effect RUNS
// Second render, name prop changes
<Greet name="Stan" />   // Side-effect DOES NOT RUN
// Third render, name prop changes
<Greet name="Butters"/> // Side-effect DOES NOT RUN
Copy the code

Running Demo online

3.2 Component Updates

Side effects If a value of props or state is used, then these values must be used as dependencies:

import { useEffect } from 'react';
function MyComponent({ prop }) {
  const [state, setState] = useState();
  useEffect(() = > {
    // Side-effect uses `prop` and `state`
  }, [prop, state]);
  return <div>.</div>;
}
Copy the code

UseEffect (Callback, [prop, state]) calls the callback callback only if any value in the dependent array [prop, state] changes after each render update is committed to the DOM.

With the useEffect() dependency argument, you can control when side effects are invoked, regardless of the component’s rendering cycle. This is also the essence of the useEffect() hook.

We use NameProp in document.title to modify the Greet component:

import { useEffect } from 'react';
function Greet({ name }) {
  const message = `Hello, ${name}! `;
  useEffect(() = > {
    document.title = `Greetings to ${name}`; 
  }, [name]);
  return <div>{message}</div>;
}
Copy the code

Nameprop as useEffect (… , [name]), the useEffect() hook performs side effects after the initial rendering and if the value of name changes during subsequent renderings.

// First render
<Greet name="Eric" />   // Side-effect RUNS
// Second render, name prop changes
<Greet name="Stan" />   // Side-effect RUNS
// Third render, name prop doesn't change
<Greet name="Stan" />   // Side-effect DOES NOT RUN
// Fourth render, name prop changes
<Greet name="Butters"/> // Side-effect RUNS
Copy the code

Running Demo online

4. Cleaning up side effects

There are some side effects that need to be cleaned up: closing sockets, clearing timers, etc.

If the useEffect(callback, deps) callback returns a function, then useEffect() considers it a side effect cleanup function:

useEffect(() = > {
    // Side-effect...
    return function cleanup() {
      // Side-effect cleanup...
    };
}, dependencies);
Copy the code

The cleaning process is as follows:

  1. After the initial rendering is complete,useEffect()Calls a callback with side effects, at which point the cleanup function is not called.
  2. In later renderings, before the next side effect callback,useEffect()The cleanup function from the last side effect execution is called first (to clean up the products of the previous side effect execution), and then the current side effect is run.
  3. Finally, after the component is uninstalled,useEffect()Calls the cleanup function for the last side effect.

Let’s look at an example of a side effect cleanup in action.

The following component
receives a propMessage and prints the message in the console every 2 seconds:

import { useEffect } from 'react';
function RepeatMessage({ message }) {
  useEffect(() = > {
    setInterval(() = > {
      console.log(message);
    }, 2000);
  }, [message]);
  return <div>I'm logging to console "{message}"</div>;
}
Copy the code

Running Demo online

Open up the sample code and type something, and the console prints the input every 2s, but we really just need the latest message.

This is an example of a cleaning side effect: cancel the previous timer and start a new one. We return a cleanup function in our code that stops the previous timer:

import { useEffect } from 'react';
function RepeatMessage({ message }) {
  useEffect(() = > {
    const id = setInterval(() = > {
      console.log(message);
    }, 2000);
    return () = > {
      clearInterval(id);
    };
  }, [message]);
  return <div>I'm logging to console "{message}"</div>;
}
Copy the code

Running code online

Open demo and type some messages: only the latest messages will be printed to the console

5. UseEffect (

5.1 Obtaining Data

UseEffect () can perform side effects that retrieve data.

The following component FetchEmployees obtains a list of employees via a network request:

import { useEffect, useState } from 'react';
function FetchEmployees() {
  const [employees, setEmployees] = useState([]);
  useEffect(() = > {
    async function fetchEmployees() {
      const response = await fetch('/employees');
      const fetchedEmployees = awaitresponse.json(response); setEmployees(fetchedEmployees); } fetchEmployees(); } []);return (
    <div>
      {employees.map(name => <div>{name}</div>)}
    </div>
  );
}
Copy the code

After the DOM completes its first mount, useEffect() initiates a request for data by calling the fetchEmployees() asynchronous function.

When the request completes, setEmployees(fetchedEmployees) updates the status of employees with the list of employees just obtained.

Note that the useEffect(callback) callback cannot be asynchronous, but you can define the asynchronous function inside the callback first and call it: useEffect(callback)

function FetchEmployees() {
    const [employees, setEmployees] = useState([]);
    useEffect(() = > {  // <--- CANNOT be an async function
      async function fetchEmployees() {
        // ...
      }
      fetchEmployees(); // <--- But CAN invoke async functions} []);// ...
}
Copy the code

To run a request to get data based on the value of prop or state, just specify the dependency required by the request in the dependency parameters: useEffect(fetchSideEffect, [prop, stateValue]).

Conclusion 6.

UseEffect (callback, dependencies) is a hook that handles side effects in a functional component. The callback argument is a function in which the logic of the side effects is stored. Dependencies are props or state status values.

UseEffect (callback, dependencies) executes the callback after the initial loading is complete or after the dependent parameter changes during subsequent rendering.

The next step in mastering useEffect() is to understand and avoid the infinite loop trap

Write in the last

If you find this article useful, please give it a like

Small praise is a great motivation for my writing ❤️❤️❤️