React -- the use and precautions of useState

1. Basic use

useStateIt is a hook function provided by react to define responsive variables. The basic syntax is as follows:

const [count, setCount] = useState(initialCount)
  • It returns a state and a method to modify the state, and the state needs to be modified through this method;
  • initialCountIt is an initial state we pass in, it is lazy, we can pass a function to return a value as the initial state, and this function will only be executed once during the initial rendering;
const [count, setCount] = useState(() => {
    const initialCount = someExpensiveComputation();
    return initialCount
})

Next, apply the defined state to the page:

import { useState } from 'react'
function App() {
    const [count, setCount] = useState(0)
    const handleClick = () => {
        setCount(count + 1)
        // 传入一个函数,更新的值是基于之前的值来执行
        // setCount(count => count + 1)
    }
    return (
    	<div>
        	<h4>count: {count}</h4>
            <button onClick={ handleClick }>点击更新状态</button>
        </div>
    )
}

After the page is rendered, we can see countthat the value of is 0. When we click the button, countthe value of will be increased by 1, and the page will be updated at the same time;

insert image description here

After understanding the basic usage, we can think about several questions;

  • setCountIs it synchronous or asynchronous when modifying the value?
  • setCountWhat happens with consecutive calls ?

First question: setCountis it synchronous or asynchronous when modifying the value?

const handleClick = () => {
    console.log("value1: ", count)
    setCount(count => count + 1)
    console.log("value2: ", count)
}

insert image description here

From the figure, we can see that the value of the page is updated, but the console prints the previous value. Does this also mean that setCountit is asynchronous? Let's change the method and use asynchronous to modify the state;

const handleClick = () => {
    console.log("value1: ", count)
    setTimeout(() => {
        setCount(count => count + 1)
        console.log("value2: ", count)
    }, 0)
}

insert image description here

Obviously, the result of asynchronously modifying the state is the same as synchronously modifying the state, which also shows setCountthat is updated asynchronously; then how do we get the updated value? We can use another hook function useRef, the code is as follows:

function App() {
  const [count, setCount] = useState(0)
  const countRef = useRef(count)
  countRef.current = count
  const handleClick = () => {
    setCount(count => count + 1)
    console.log("value3: ", count)
    setTimeout(() => {
      console.log(countRef.current)
    }, 0)
  }
  return (
    <div>
      <h4>count: {count}</h4>
      <button onClick={handleClick}>点击更新状态</button>
    </div>
  )
}

insert image description here

From the figure, we can see that we have obtained the updated value, which useRefcan not only be used to access DOM nodes, but also can be used to represent a container. currentThe property can hold any value, and useRefthe returned object will be maintained throughout the life cycle. ;

Second question: what setCounthappens ?

(1) Pass in a state-based value

const handleClick = () => {
    console.log("value1: ", count)
    setCount(count + 1)
    console.log("value2: ", count)
    setCount(count + 1)
    console.log("value3: ", count)
}

insert image description here

As can be seen from the picture, if we pass in an ordinary value, it will only be updated for the last time;

(2) Pass in a function

const handleClick = () => {
    console.log("value1: ", count)
    setCount(count => count + 1)
    console.log("value2: ", count)
    setCount(count => count + 1)
    console.log("value3: ", count)
}

insert image description here

It can be seen that if a function is passed in, it will perform two assignments, because the updated value is executed based on the previous value, so it is recommended to modify it in the form of function passing in during development;

2. Matters needing attention

1. Modification of complex variables

For variables of complex types, we need to redefine when we modify them. Modifications based on the original data will not cause re-rendering of components, because the update mechanism of React components only performs shallow comparisons, that is, when updating a complex type of data, only its If the reference address does not change, the component will not be re-rendered; for example

function App() {
    const [arr, setArr] = useState([1])
    const pushData = () => {
        arr.push(4)
        setArr(arr)
    }
    return (
        <div>
            <h4>{arr.join("-")}</h4>
            <button onClick={pushData}>点击添加数组</button>
        </div>
    )
}

When the above code clicks the button, the view will not change, but the value arrof change. If you want to modify this array, you need to redefine an array to modify it. The modification on the original array will not cause the component to re-render. React components The update mechanism only performs a shallow comparison, that is, when updating a complex type of data, as long as its reference address does not change, the component will not be re-rendered;

const pushData = () => {
    setArr([...arr, 4])
}

2. Asynchronous operation to get updated value

In a class component, the updated value can be obtained by asynchronous operation when modifying the value, but in the function component, the updated value cannot be obtained by asynchronous acquisition. For example, compare:

class component

class App extends React.Component {
    constructor() {
        super()
        this.state = {
            count: 0
        }
    }
    handleClick = () => {
        this.setState({
            count: this.state.count + 1
        })
        console.log(this.state.count)
        setTimeout(() => {
            console.log(this.state.count)
        })
    }
    render() {
        return (
            <>
            <h4>count: {this.state.count}</h4>
            <button onClick={this.handleClick}>点击更新状态</button>
            </>
        );
    }
}

insert image description here

function component

function App() {
    const [count, setCount] = useState(0)
    const handleClick = () => {
        setCount(count => count + 1)
        console.log("value1: ", count)
        setTimeout(() => {
            console.log("value2: ", count)
        })
    }
    return (
        <div>
            <h4>count: {count}</h4>
            <button onClick={handleClick}>点击更新状态</button>
        </div>
    )
}

insert image description here

Obviously, the updated value cannot be obtained asynchronously in a function component, we can obtain useRefit through ;

const countRef = useRef(count)
countRef.current = count
const handleClick = () => {
    setCount(count => count + 1)
    console.log("value1: ", countRef.current)
    setTimeout(() => {
        console.log("value2: ", countRef.current)
    })
}

Guess you like

Origin blog.csdn.net/Ljwen_/article/details/125319191