React 的 setState 方法与 prevState 参数

IT技术 javascript reactjs
2021-04-15 09:15:50

我是 React 的新手,只是有一个关于 setState 方法的问题。假设我们有一个组件:

class MyApp extends React.Component {

  state = {
    count: 3
  };

  Increment = () => {
    this.setState((prevState) => ({
      options: prevState.count + 1)
    }));
  }
}

那么为什么我们要prevStatesetState方法中使用呢?为什么我们不能这样做:

this.setState(() => ({
  options: this.state.count + 1)
}));
6个回答

两种签名都可以使用,唯一的区别是如果您需要根据之前的状态更改您的状态,您应该使用this.setState(function)它将为您提供prevState之前状态的快照()。但如果更改不依赖于任何其他先前的值,则建议使用较短的版本this.setState({prop: newValue})

this.setState(prevState =>{
   return{
        ...prevState,
        counter : prevState.counter +1
   }
})

this.setState({counter : 2})
确实如此。从文档The first argument is an updater function with the signature: (state, props) => stateChange. state is a reference to the component state at the time the change is being applied. It should not be directly mutated此外,prevState.counter当您只想增加后者时,为什么要更新和返回对象计数器?从理论上讲,您还可以拥有另一个依赖的密钥,prevState.counter如果您这样做,它将无法工作++说,someCountDown: prevState.counter - 1
2021-06-02 09:15:50
我只是说这是一种不好的做法。过去我自己也犯过这个确切的错误并且遇到了问题。
2021-06-14 09:15:50
感谢您的建议!
2021-06-19 09:15:50
不要这样做,prevState.counter++因为这会发生变异prevStateprevState.counter + 1代替。
2021-06-21 09:15:50
变量已更新,但我正在生成一个新属性,该属性仅反映先前状态的实际计数器
2021-06-21 09:15:50
class MyApp extends React.Component {

  state = {
    count: 0
  };

  Increment = () => {
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
  };

  IncrementWithoutPrevState = () => {
    this.setState(() => ({
      count: this.state.count + 1
    }));
    this.setState(() => ({
      count: this.state.count + 1
    }));
    this.setState(() => ({
      count: this.state.count + 1
    }));
    this.setState(() => ({
      count: this.state.count + 1
    }));
  };

  render() {
    return (
      <div>
        <button onClick={this.IncrementWithoutPrevState}>
          Increment 4 times without PrevState
        </button>
        <button onClick={this.Increment}>
          Increment 4 times with PrevState
        </button>
        <h1>Count: {this.state.count}</h1>
      </div>
    );
  }
}

我只是举了一个例子让你了解“React 可以批处理多个 setState()...”是什么意思,以及为什么我们应该在上面的场景中使用 prevState。

首先,试着猜一下Count当你点击两个按钮时会产生什么结果......如果你认为点击两个按钮count都会增加 4,那么这不是正确的猜测;)

为什么?因为IncrementWithoutPrevState方法,因为有多个setState电话,等react过来批量所有这些电话,并更新state只在最后调用setState这个方法,所以在最后一次通话的时间,setState在这个方法this.state.count还没有被更新,其value仍然是相同的那是在进入IncrementWithoutPrevState方法之前,因此结果状态将包含count递增 1。

现在另一方面,如果我们分析该Increment方法: 再次有多个setState调用并且 React 将它们全部批处理,这意味着实际状态将在最后一次调用中更新,setStateprevState将始终包含state在最近setState调用中修改的状态由于previousState.count值已经增加了 3 次,直到最后一次调用,setState因此结果state将包含增加了 4 的计数值。

这里是每个人都知道 state:prevstate.counter+1.. 我们也可以用 state:this.state.counter+1 来做到这一点。这不是我认为使用 prevstate 的方式。当我进入现有状态时,我在数组中遇到问题它允许我但第二次它阻止更改

如果在单个render()函数调用中多次调用一个函数来更改状态属性的值,则更新的值将不会在没有 prevState 机制的不同调用之间传递。

second(){
   this.setState({ // no previous or latest old state passed 
       sec:this.state.sec + 1
     }, ()=>{
        console.log("Callback value", this.state.sec)
   })    
}

fiveSecJump(){ // all this 5 call will call together  
       this.second() // this call found sec = 0 then it will update sec = 0 +1
       this.second() // this call found sec = 0 then it will update sec = 0 +1
       this.second() // this call found sec = 0 then it will update sec = 0 +1
       this.second() // this call found sec = 0 then it will update sec = 0 +1
       this.second() // this call found sec = 0 then it will update sec = 0 +1
   }

  render() {
        return (
            <div>
              <div>  Count - {this.state.sec}</div>
              <button onClick ={()=>this.fiveSecJump()}>Increment</button>
            </div>
        )
    }

最后 sec 值将是 1,因为调用是异步的,不像 c++/c# 或 java 这样的高级编程语言总是有一个维护主线程的 main 函数。
因此,如果你想让fiveSecJump()函数正常工作,你必须通过向它传递一个箭头函数来帮助它。上一个状态。prevState 不是关键字或成员函数,你可以在这里写任何词,如 oldState、stackTopState、lastState。它将转换为通用函数,可以完成您想要的工作。

class Counter extends Component {
   constructor(props){
        super(props)
        this.state = {
            sec:0
        }
   }
   second(){
        this.setState(prevState =>({
            sec:prevState.sec + 1
        }))
   }

   fiveSecJump(){
       this.second() // this call found sec = 0 then it will update sec = 0 +1
       this.second() // this call found sec = 1 then it will update sec = 1 +1
       this.second() // this call found sec = 2 then it will update sec = 2 +1
       this.second() // this call found sec = 3 then it will update sec = 3 +1
       this.second() // this call found sec = 4 then it will update sec = 4 +1

   }
    render() {
        return (
            <div>
              <div>  Count - {this.state.sec}</div>
              <button onClick ={()=>this.fiveSecJump()}>Increment</button>
            </div>
        )
    }
}

export default Counter
//Here is the example to explain both concepts:


import React, { Component } from 'react'

export default class Counter extends Component {
    constructor(props) {
        super(props);
        this.state = { counter: 0 }
    }

    increment() {
        this.setState({counter:this.state.counter+1})
    }

    increment3() {
        this.increment();
        this.increment()
        this.increment()
    }
   render() {
        return (
            <div>
               count-{this.state.counter}
                <div>
                    <button onClick={() => this.increment3()}>Increment</button>
                </div>
            </div>

        )
    }
}

在这种情况下,当我们单击Increment按钮时,输出将呈现到 UI 中是count-0而不是count-3,因为 react 将所有状态调用分组到单个状态调用中​​,并且不会在每个递增的调用中携带更新的值。如果我想根据以前的值更新值,请使用下面提到的代码。

import React, { Component } from 'react'

export default class Counter extends Component {
    constructor(props) {
        super(props);
        this.state = { counter: 0 }
    }

    increment() {
        this.setState((prevState=>({counter:prevState.counter+1})))
    }

    incremental() {
        this.increment();
        this.increment()
        this.increment()
     
    }
   render() {
        return (
            <div>
               count-{this.state.counter}
                <div>
                    <button onClick={() => this.incremental()}>Increment</button>
                </div>
            </div>

        )
    }
}

在这种情况下,输出将是count-3而不是count-0