在循环中调用 setState 只会更新状态 1 次

Posted

技术标签:

【中文标题】在循环中调用 setState 只会更新状态 1 次【英文标题】:Calling setState in a loop only updates state 1 time 【发布时间】:2016-05-16 21:10:23 【问题描述】:

是否有理由在循环中调用setSate() 会阻止它多次更新状态?

我有a very basic jsbin,它突出了我看到的问题。有两个按钮。一个将状态计数器更新 1。另一个在循环中调用 One 的底层函数——这似乎会多次更新状态。

我知道这个问题的几种解决方案,但我想确保我首先了解这里的底层机制。为什么不能循环调用setState?我的代码是否笨拙而妨碍了预期的效果?

【问题讨论】:

【参考方案1】:

其实setState() 方法是异步的。相反,您可以像这样实现它

manyClicks() 
var i = 0;
for (i = 0; i < 100; i++) 
  //this.setState(clicks: this.state.clicks + 1); instead of this
  this.setState((prevState,props)=>(
      clicks: ++prevState.clicks
   ))
   
 

【讨论】:

【参考方案2】:

来自React Docs:

setState() 将组件状态更改入队并告诉 React 该组件及其子组件需要使用更新后的状态重新渲染。这是您用来更新用户界面以响应事件处理程序和服务器响应的主要方法。

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

setState() 并不总是立即更新组件。它可能会批量更新或将更新推迟到以后。这使得在调用setState() 之后立即阅读this.state 是一个潜在的陷阱。

基本上,不要循环调用setState。这里发生的事情正是文档所指的:this.state 正在返回以前的值,因为尚未应用挂起的状态更新。

【讨论】:

因为他打电话给this.setState(clicks: this.state.clicks += 1);,这真是个坏主意。 += 直接改变状态,而不是让 React 通过 setState 批量更新来完成。 我不知道我是如何在文档中错过的,但谢谢。这更有意义。 请注意,setState 有一种形式,它接受一个函数并允许您访问当前状态,并且在这种情况下确实有效。有关示例,请参见 jsbin.com/kiyaco/edit?js,output。 不错。我其实不知道你可以将函数传递给setState 这个答案节省了我一周的上传状态处理,tvm【参考方案3】:

你必须使用类似的东西:

const MyComponent = () => 
  const [myState, setMyState] = useState([]);

  const handleSomething = (values) => 
    values.map((value) => 
      setMyState((oldValue) => [...oldValue,  key: value.dataWhatYouWant ]);
    
  

  return (<> Content... </>);

【讨论】:

【参考方案4】:

我在创建导入项目的功能时遇到了这个问题。 由于导入项目的数量可能很大,我需要向站点用户提供反馈(如进度条),以便他们知道他们不会坐在那里等待。

我们知道我们不能在循环中setState,所以我采用了另一种方法,递归地运行任务。

这是一个示例代码 https://codesandbox.io/s/react-playground-forked-5rssb

【讨论】:

【参考方案5】:

有一种在循环中更新状态的好方法。只需创建一个空变量,将其值设置为更新状态,调用setState(),并将此变量传递给它:

const updatedState = ;

if (vars.length) 
  vars.forEach(v => 
    updatedState[v] = '';
    this.setState(
      ...this.state
      ...updatedState,
    );
  );

【讨论】:

哇,完美而干净的方法可以绕过多个调用的 React 优化,如果 setState 被打成一个。【参考方案6】:

基本上 setState 是异步调用的。它还有一个回调函数,一旦状态发生突变,您就可以利用它来做一些事情。 此外,如果多个 setState 一个接一个地被调用,它们会像之前写的那样被批处理。

【讨论】:

【参考方案7】:

我遇到了同样的问题。但尝试了一些不同的方法。

iterateData(data)
  //data to render
   let copy=[];
   for(let i=0;<data.length;i++)
     copy.push(<SomeComp data=[i] />) 
    
    this.setState(
      setComp:copy
    );
 
 render()
   return(
     <div>
       this.state.setComp
    </div>
   );
 

我希望这会有所帮助。

【讨论】:

【参考方案8】:

我能够让你的代码工作,通过执行以下操作在循环中调用 setState:

 manyClicks() 
   for (i = 0; i < 100; i++) 
     this.setState(clicks: this.state.clicks += 1)
   
 
enter code here

希望这会有所帮助!

【讨论】:

以上是关于在循环中调用 setState 只会更新状态 1 次的主要内容,如果未能解决你的问题,请参考以下文章

ComponentDidMount 中调用的 setState 没有更新状态? [复制]

在颤振中从父小部件调用 setState 不会更新状态

在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState。 React 限制嵌套更新的数量以防止无限循环

更新状态 - 为啥在调用 setState 时创建新的状态副本?

在render()中更新状态时,防止无限循环

调用 setState 时,我的有状态小部件不会更新其状态