即使使用setTimeOut之后,setState也会立即更新

时间:2019-10-24 07:25:49

标签: javascript reactjs

我有一个包含10个元素的div,这些元素将被逐个更新,延迟时间为2秒。下面是相同的代码

for(let boxNo=0; boxNo<10; boxNo++){
  setTimeout(() => {
    nodes[boxNo].isMarked = true;
    this.setState({nodes});
    }, (boxNo*200)+boxNo);
  );
}

但是当我运行它时,所有元素都会一起更新。该程序只是添加一个延迟添加一个开始,并且所有元素都一起更新(被标记)。如何制作代码来逐一标记元素?

3 个答案:

答案 0 :(得分:2)

您正在打破React的两个基本规则:

  1. Don't mutate state directly

    for(let boxNo=0; boxNo<10; boxNo++){
      setTimeout(() => {
        nodes[boxNo].isMarked = true; // <==== here
        this.setState({nodes});
        }, (boxNo*200)+boxNo);
      );
    }
    
  2. 如果根据现有状态更新状态,请use the callback form,因为状态更新可能是异步的(无论如何,在您的示例中,时间已经过去了):

    for(let boxNo=0; boxNo<10; boxNo++){
      setTimeout(() => {
        nodes[boxNo].isMarked = true;
        this.setState({nodes});       // <==== here
        }, (boxNo*200)+boxNo);
      );
    }
    

相反,请参见***注释和相关代码:

// **IF** `nodes` is an array
for(let boxNo=0; boxNo<10; boxNo++){
  setTimeout(() => {
    // *** Note using callback form (#2)
    this.setState(({nodes} => {
        // *** *Copy* the parts of state you're going to modify (#1)
        nodes = [...nodes];
        nodes[boxNo] = {...nodes[boxNo], isMarked: true};
        return {nodes};
    });
    }, (boxNo*200)+boxNo);
  );
}

setState的调用也可以这样编写,但要花费创建临时对象的代价(<琐碎):

this.setState(({nodes} => ({
    nodes: Object.assign([], nodes, {[boxNo]: {...nodes[boxNo], isMarked: true}})
});

// **IF** `nodes` is a non-array object
for(let boxNo=0; boxNo<10; boxNo++){
  setTimeout(() => {
    // *** Note using callback form (#2)
    this.setState(({nodes} => {
        // *** *Copy* the parts of state you're going to modify (#1)
        return {
            nodes: {
                ...nodes,
                [boxNo]: {...nodes[boxNo], isMarked: true}
            }
        };
    });
    }, (boxNo*200)+boxNo);
  );
}

答案 1 :(得分:0)

setTimeout会在您的循环中首次计算200。

尝试将时间增加更多毫秒。

  

3秒(3000毫秒)

    for(let boxNo=0; boxNo<10; boxNo++){
(function(x){
      setTimeout(function(){
        nodes[boxNo].isMarked = true;
        this.setState({nodes});
        }, ((x+1)*3000)+x);}
      )(boxNo);
    }

答案 2 :(得分:0)

这对我来说很好。

 (function loop (boxNo) {          
  setTimeout(function () {   
     nodes[boxNo].isMarked = true;
     this.setState({nodes});                
     if (--boxNo) loop(boxNo);    // decrementing i and calling loop function again if i > 0
  },  ((boxNo+1)*2000)+boxNo)
})(10);