Reactjs-setState 前一个状态是第一个参数,props 作为第二个参数

Posted

技术标签:

【中文标题】Reactjs-setState 前一个状态是第一个参数,props 作为第二个参数【英文标题】:Reactjs-setState previous state is the first argument, props as the second argument 【发布时间】:2018-11-23 01:28:45 【问题描述】:

我在这篇官方文章中读到了以下几行:

this.propsthis.state 可能会异步更新,您不应依赖它们的值来计算下一个状态。

谁能通过举个例子向我解释以下代码试图实现的目标。

 this.setState((prevState, props) => (
  couter: prevState.counter + props.increment
));

I am referring to this official website of reactjs React.js

【问题讨论】:

【参考方案1】:

他们说你应该这样做而不是下面的例子。

// Wrong
this.setState(
  counter: this.state.counter + this.props.increment,
);

如果您像这样访问,他们无法保证状态将具有正确的值,因为 setState() 将异步发生,可能会发生其他更新并更改值。如果你要根据之前的状态计算状态,你必须确保你有最新的和最新的值,所以他们让 setState() 接受一个被调用的函数prevStateprops,因此您可以使用正确的值来更新您的状态,如下例所示。

 // Correct
this.setState((prevState, props) => (
  counter: prevState.counter + props.increment
));

【讨论】:

【参考方案2】:

为了补充布鲁诺的答案,上面的正确函数称为 pure 函数。 React 在一个叫做immutability 的东西上很重要,这意味着如果可能的话,每个声明的值都不应该从它的原始声明中改变。该函数中的变量在您传入之前不是您的实际道具和状态,这意味着在 javascript 函数堆栈(排队同步和异步调用的线程)上,值和对属性的引用将以不同方式存储,从而产生不确定性在“错误”情况下的值是多少。

【讨论】:

谢谢。函数是无状态的,类不在 Reactjs 中?【参考方案3】:

React 可以将多个 setState() 调用批处理到单个更新中以提高性能。

由于this.propsthis.state 可能会异步更新,因此您不应依赖它们的值来计算下一个状态。

来自https://reactjs.org/docs/react-component.html#setstate:

setState() 将组件状态更改入队并告诉 React 这个组件及其子组件需要重新渲染 更新状态。

setState() 视为请求,而不是直接命令 更新组件。为了获得更好的感知性能,React 可能 延迟它,然后一次更新几个组件。反应 不保证立即应用状态更改。

通过示例了解

这个概念可能很难理解,特别是为什么它会导致问题,所以我写了一个例子来显示发生的错误:

/* Imagine props and states is the same as this.props and this.state */
var state =  counter: 0  ; var props =   ;

/* Our fake implementation of react setState */
var setStatesToRun = []
function setState(myFunction)  setStatesToRun.push(myFunction); 

/* Our fake implementation of react batch update */
function batchRunStateUpdates() 
  propsLocal = props
  stateLocal = state

  f1 = setStatesToRun.pop()
  newState = f1(stateLocal, propsLocal)  // Will run increment by 3
  console.log(newState) // newState:  counter: 3 
  console.log(state) // state:  counter: 0 

  f2 = setStatesToRun.pop()
  newState = f2(newState, propsLocal) // Will run increment by 2
  console.log(newState) // newState:  counter: 2 
  console.log(state) // state:  counter: 0 

  // ... get the next setState function loop

  console.log("Will update global state")
  state = newState  
  console.log(state) // state:  counter: 2  // WRONG!


console.log(setStatesToRun) // []

// Right
setState((prevState, props) =>  counter: prevState.counter + 3 );

// WRONG, using state (this.state)
setState((prevState, props) =>  counter: state.counter + 2 );

console.log(setStatesToRun) // [func, func]

batchRunStateUpdates();

在顶部,我们有一些 React 方法的虚假版本。这些过于简化,但有助于解释发生了什么。

然后,我们像在 React 中一样使用 setState。一种用法是对的,另一种是错误的。

请注意,最终的全局状态应该是 state: counter: 5 ,但由于我们不尊重 React 的建议,我们得到了 state: counter: 2

你可以在https://jsfiddle.net/oniltonmaciel/g96op3sy/玩这个代码

【讨论】:

以上是关于Reactjs-setState 前一个状态是第一个参数,props 作为第二个参数的主要内容,如果未能解决你的问题,请参考以下文章

为啥干不过苹果?某手机老总一语道破心中所想,赚钱才是第一位的

手动封装分页组件(Vue3)

用Python 创建一个工资结算程序,商量的报酬是第一天20元,第二天是第一天的2倍?

哪个 NSTextView 是第一响应者?

UITextField 始终是第一响应者

Golang泛型编程初体验