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

Calling setState in a loop only updates state 1 time

本文关键字:更新 状态 setState 循环 调用      更新时间:2023-09-26

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

有一个非常基本的jsbin,可以突出显示我所看到的问题。有两个按钮。一个将状态的计数器更新为 1。另一个在循环中调用 One 的底层函数——它似乎会多次更新状态。

我知道这个问题有几种解决方案,但我想确保我首先了解这里的潜在机制。为什么不能在循环中调用setState?我是否编码得很笨拙,从而阻止了预期的效果?

来自 React 文档:

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

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

setState()并不总是立即更新组件。它可能会批处理或推迟更新,直到以后。这使得在调用setState()后立即阅读this.state成为潜在的陷阱。

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

有一种

很好的方法可以在循环中更新状态。只需创建一个空变量,将其值设置为更新状态,调用 setState() ,然后传递给它这个变量:

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

你必须使用这样的东西:

const MyComponent = () => {
  const [myState, setMyState] = useState([]);
  const handleSomething = (values) => {
    values.map((value) => {
      setMyState((oldValue) => [...oldValue, { key: value.dataWhatYouWant }]);
    }
  }
  return (<> Content... </>);
}

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

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>
   );
 }

我希望这有所帮助。

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

实际上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
   }))
   }
 }

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

由于我们知道我们不能在循环中setState,因此我采取了不同的方法,以递归方式运行任务。

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

您可以使用以前的值尝试此操作以增加计数。

function handleChange() {
    for (let i = 0; i < 5; i++) {
        setState(prev => {
            return prev + 1
        })
    }
}

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

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

希望这有帮助!