UseEffect does not use dependencies – every render is invoked

UseEffect 🤓🤓🤓 This is where the concept of Capture Value is introduced. This is a big hole. I had a lot of hooks when I first got them. I’m going to use capture Value in a small demo to discuss this concept.

Function components can store state (using useState), but they can’t handle side effects on asynchronous requests, so React provides useEffect to help developers handle side effects of function components. When making components with Class, you often use lifecycle functions to handle extra things (side effects: actions performed at specific times or events, such as Ajax requests for back-end data, adding login listeners and cancelling logins, manually modifying the DOM, and so on). A similar lifecycle function is needed in React Hooks, such as useEffect, which executes on every State update.

Note: useEffect is executed in order!! If useEffect does not pass the second argument (without passing dependencies), not only will the initial render be executed, but useEffect will be triggered whenever any state value is set to change!! React calls the useEffect function for the first rendering and every subsequent update

1. Examples of using class components and function components to implement subcomponents:

import React, { Component } from "react"; class App extends Component { state = { count: 1 }; componentDidMount() { const { count } = this.state; document.title = "componentDidMount" + count; this.timer = setInterval(() => { this.setState(({ count }) => ({ count: count + 1 })); }, 1000); } componentDidUpdate() { const { count } = this.state; document.title = "componentDidMount" + count; }}Copy the code

In the example, the component updates the component state every second, and every time the update is triggered, document.title is updated (side effect), and document.title is modified (similar to cleanup) when the component is unloaded.

As you can see from the examples, some of the repetitive features developers need to write repeatedly at componentDidMount and componentDidUpdate, which is completely different if you use useEffect.

import React, { useState, useEffect } from "react"; let timer = null; function App() { const [count, setCount] = useState(0); useEffect(() => { document.title = "componentDidMount" + count; },[count]); useEffect(() => { timer = setInterval(() => { setCount(prevCount => prevCount + 1); }, 1000); // return an arrow function to clear timer return () => {document.title = "componentWillUnmount"; clearInterval(timer); }; } []); return ( <div> Count: {count} <button onClick={() => clearInterval(timer)}>clear</button> </div> ); }Copy the code

We use useEffect to rewrite the above example. The first parameter transfer function, useEffect, can be used to do some side effects such as asynchronous requests, modifying external parameters, etc. The second parameter is an array, and the function in the first parameter is triggered only if the value in the array changes. There are two cases: 1. The dependency is [] empty array, indicating that it is executed at first render and unload; 2 has dependencies. UseEffect is re-executed when the dependencies change. If there is a return value (if there is one) there is a cleanup function, which is run before each side function is run and called before the component is destroyed or the function is called.

Two, important!! UseEffect (FN, [])

GetData (); useEffect (); useEffect (); useEffect (); getData (); useEffect ()

1. Call const getData=()=>{console.log(11111); } useEffect(getData,[]) // This code indicates that the getData callback is executed on the first renderingCopy the code

2. The following code calls the getData callback and passes in the parameters on the first render.

Const getData= (params) =>{console.log(params); } useEffect(()=>{getData(222)},[]Copy the code

3. Focus!! UseEffect to send ajax requests

Note that async cannot be used directly in useEffect. The console error also provides a solution: place async in useEffect.

useEffect(() => { const fetchData = async () => { const result = await axios('https://hn.algolia.com/api/v1/search?query=redux'); setData(result.data); } fetchData(); Console. log(' executed ')},[]); = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = or direct solution put this call interface request method outside const fetchData = async () = > {const result = await axios('https://hn.algolia.com/api/v1/search?query=redux'); setData(result.data); } useEffect (() = > {fetchData () the console. The log (' performed ') / / request method here is bracketed}, [])Copy the code

Third, the understanding of the cleaning function

Analysis of the cleanup function execution time point below: Cleanup function is not executed when the render is first mounted, and its execution time point is executed before each side function is run. Note that component destruction also calls cleanup functions

To prevent memory leaks, the cleanup function is executed before the component is unloaded; If the component renders more than once (as is usually the case), the previous effect is cleared before the next effect is executed, by executing the function that returned in the previous effect and then executing the function that did not return in this effect.

To further understand the cleanup function, turn on the elimination timer:

Important: This involves closure issues: I have encountered this problem in previous projects where the initial request was always given the default value, not the status value of the request’s control center switch button !!!! Use useEffect to get the updated variable value!!

  1. In the first example above, the idea of [count] in the useEffect dependency is to modify the documen.title value whenever the count value changes
  2. The second useEffect is used instead of componentDidMount and componentWillUnmount. The second useEffect is used instead of componentDidMount and componentWillUnmount
  1. UseEffect returns a function, that is, a cleanup function, which is run every time the side effect function is run, that is, before the component is destroyed or the function is called

Based on this powerful Hooks, we can emulate and encapsulate other life cycle functions, such as componentDidUpdate code is very simple:

  • UseEffect: the second argument to useEffect is an empty array that is not executed after the initial call, emulating componentDidMount.
  • When useEffect has no second argument, component initialization and updating are performed, emulating componentDidMount and componentWillUnmount.
  • UseEffect returns a function that is executed when the component is uninstalled. Simulation componentDidMount componentWillUnmount

In short, pass in a dependency, and whenever the dependency changes, useEffect is executed again; No dependencies are passed in and are called for the first render and every subsequent render

import React, { useState, useEffect } from "react"; let timer = null; function App() { const [count, setCount] = useState(0); UseEffect (() => {document.title = "componentDidMount" + count; },[count]); useEffect(() => { timer = setInterval(() => { setCount(prevCount => prevCount + 1); }, 1000); // return an arrow function to clear timer return () => {document.title = "componentWillUnmount"; clearInterval(timer); }; } []); return ( <div> Count: {count} <button onClick={() => clearInterval(timer)}>clear</button> </div> ); }Copy the code

4. Conclusion: Pay attention to useEffect

  1. React: useEffect () is used for the first rendering and every subsequent update of the React component. UseEffect () is used for the first rendering and every subsequent update of the React component. However, it is important to note that useEffect is performed after the actual DOM has been rendered; But DidMount and DidUpdate are implemented before the real DOM is complete; Previously in the class component, we used two lifecycle functions to represent first render (componentDidMonut) and re-render due to update (componentDidUpdate).
  2. UseEffect defines functions that execute asynchronously without preventing the browser from updating the view, whereas the code in componentDidMonut and componentDidUpdate are executed synchronously.
  1. The useEffect cleanup function is executed before each side effect function is run, that is, before the component is destroyed or the function is called

When using useEffect, it is important to select the dependency. If some dependencies are not added, forcing eslint-disable-line to skip rule verification may cause a problem with Capture Value. I recently checked the Capture Value pit encountered in the previous project. Add a joy to your audience 🤣🤣🤣