Come and join us!

“Novices of The Mountain”, provides technical information and a series of basic articles for front-end developers. For a better user experience, please move to our website xiaohe Shan rookies (xhs-rookies.com/) to learn and get the latest articles.

“Code Tailor “, if you are interested in our article or want to make some suggestions, follow the official account of “Cainiao of Xiaohe Mountain” on wechat and contact us. You can also watch our article on wechat. Every suggestion or approval is a great encouragement to us!

preface

In this article, our main goal is to look at the use of a shared state hook (useEffect).

useEffect

define

Effect Hooks allow you to perform side effects in a function component. In other words, you can do something similar to the Class lifecycle.

How to use

UseEffect () is used as follows.

useEffect(() = > {
    dosomeing(); // Perform some side effects
},[]);
Copy the code

UseEffect requires an argument

  • First argument: The Hook receives a function that contains imperative code that may have side effects.

  • The second argument: the useEffect is executed only when the state has changed.

What does useEffect do

UseEffect hooks to tell React that something needs to be done after rendering. UseEffect’s first argument requires that we pass a function that will be executed after React updates the DOM. By default, this function will be executed either after the component is first rendered or after the component is updated. In this function, we can perform some of the same lifecycle work as in a Class component, such as changing the DOM, adding subscriptions, setting timers, logging, and so on. Note that these side effects are not allowed in the function component without the useEffect Hook.

prompt

If you’re familiar with React class lifecycle functions, you can think of useEffect Hook as a combination of componentDidMount, componentDidUpdate, and componentWillUnmount.

Clear effect

In the Class component, we need to clear some side code in componentWillUnmount, such as our create timer and clear timer. Similarly, when the function component is unloaded, we also need to clear the resources created by Effect, such as subscription or timer ID. To do this, the useEffect function returns a clear function. Here is an example of creating a timer:

const [count, addCount] = useState(0)
const [timer, addTimer] = useState(1000)

useEffect(() = > {
  const interval = setInterval(() = > {
    // Create a timer
    addCount((val) = > val + 1)
  }, timer)
  return () = > {
    // Return the clear function
    clearInterval(interval) // Clear the timer}})Copy the code

To prevent memory leaks, the cleanup function is executed before the component is unloaded. In addition, if the component is rendered multiple times (as it usually is), the previous effect will be cleared before the next effect is executed. In the above example, this means that each update to the component creates a new timer. To avoid triggering effect with each update, use the second argument to useEffect.

Conditional execution of effect

By default, effect is executed after each turn component is rendered. This way, the effect will be recreated once its dependency changes.

In some cases, however, this may be overcorrecting. For example, in the example of the timer above, we don’t need to create a new timer every time the component is updated, but only recreate it when the source Prop changes.

The second argument that useEffect accepts is the array of values that effect depends on. The following is an example after the update:

const [count, addCount] = useState(0)
const [timer, addTimer] = useState(1000)

useEffect(() = > {
  const interval = setInterval(() = > {
    // Create a timer
    addCount((val) = > val + 1)
  }, timer)
  return () = > {
    clearInterval(interval) // Clear the timer
  }
}, [count])
Copy the code

When the second argument is passed in, in this case, the timer is recreated when the count changes. In other words, useEffect determines whether the update will be executed based on the second argument we passed in.

Pay attention to

  • If you are using this optimization, make sure that the array contains all variables that will change in the outer scope and be used in effect, otherwise your code will refer to old variables from previous renderings.
  • If you want to perform an effect that runs only once (only when the component is mounted and unmounted), you can pass an empty array ([]) as the second parameter.

Contrast component

Now that you know useEffect, let’s use a simple example to see the difference between using a Hook and a Class component in a function component.

There is a simple timer that counts in 1000ms intervals by default. After clicking the Add button, the timer interval increases and the timer count slows down.

Class component implementation

We first declare a variable count in the class component to count, a variable timer to control the counting interval, every timer interval, the count by one, and then add a button, each time the click of the timer increases by 1000ms. And count increases slowly.

class Example extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0.timer: 1000,}}componentDidMount() {
    this.interval = setInterval(() = > {
      // Create a timer
      this.setState({
        count: this.state.count + 1,}}),this.state.timer)
  }
  componentDidUpdate() {
    clearInterval(this.interval) // Clear the previous timer first
    this.interval = setInterval(() = > {
      // Create a timer with an updated timer interval
      this.setState({
        count: this.state.count + 1,}}),this.state.timer)
  }
  componentWillUnmount() {
    clearInterval(this.interval) // Clear the timer during uninstallation
  }

  render() {
    return (
      <div>
        <p>{this.state.count}</p>
        <p>The current count interval is {this.state.timer}ms</p>
        <button onClick={()= > this.setState({ timer: this.state.timer + 1000 })}>Click me</button>
      </div>)}}Copy the code

We can see that in this class, we need to write duplicate code in both lifecycle functions. There is a lot of repetitive code to clean up the timer when the component is unloaded. What about using Effect hooks in function components?

Implementation using Effect Hook

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

function Example() {
  const [count, addCount] = useState(0)
  const [timer, addTimer] = useState(1000)

  useEffect(() = > {
    const interval = setInterval(() = > {
      addCount((val) = > val + 1)
    }, timer)
    return () = > {
      clearInterval(interval)
    }
  }, [count])

  return (
    <div>
      <p>The current value of count is: {count}</p>
      <p>The current counting interval is {timer}ms</p>
      <button onClick={()= > addTimer((val) => val + 1000)}>Click me</button>
    </div>)}Copy the code

After looking at this example, it may be surprising to see that this function is not written in the constructor function of the Class component, and is solved by the useEffect guy in the function component! Doesn’t it look lean. I believe you have the following questions:

  • useEffectWhat did you do?

    By using this Hook, you can tell the React component that something needs to be done after rendering. React saves the function you pass (we’ll call it “effect”) and calls it after the DOM update.

  • Why call inside a componentuseEffect?

    Putting useEffect inside the component allows us to access the count State variable (or other props) directly from within the effect.

  • useEffectWill it be performed after each render?

    Yes, by default, it is performed after the first render and after each update (you can control the render conditions with the second parameter mentioned earlier). Also, React ensures that the DOM is updated every time effect is run.

summary

  • The useEffect Hook actually gives us the ability to handle side effects in a function component, such as a combination of componentDidMount, componentDidUpdate, and componentWillUnmount.

  • The useEffect Hook lifecycle is different from that of the Class function: UseEffect is executed after the DOM has been updated, componentDidMount is called immediately after the component is mounted (inserted into the DOM tree), and componentDidUpdate() is called immediately after the DOM has been updated. This method is not executed for the first render. ComponentWillUnmount () is called directly before the component is unmounted and destroyed.

  • Prior to useEffect Hooks, component development was increasingly flooded with state logic and side effects. Each lifecycle often contains some unrelated logic. It helps us to better break down the state logic, rather than forcing it into life cycles, and opens up a lot of possibilities for development.

Next day forecast

Stay tuned for an introduction to useRefs in the next section!