在.forEach循环中使用setState将仅以最新状态运行回调函数?

时间:2018-12-26 20:00:07

标签: javascript reactjs

我有一个tempAddList,它将包含一个ID列表,我将把状态设置到relInfo表中,并回调addRelation函数以提交数据。但是,例如当我运行onAddClick时,如果tempAddList = [2,3,4] 它会使用最新的setState id 4运行addRelation 3次,但不会运行2和3。我如何让它针对每个单独的id运行。

  final String url = "http://api.azanpro.com/times/today.json?zone=ngs02&format=12-hour";
  List data;

  Future<String> getSWData() async {
    var res = await http
        .get(Uri.encodeFull(url), headers: {"Accept": "application/json"});

    setState(() {
      var resBody = json.decode(res.body);
      data = resBody["prayer_times"];
    });

1 个答案:

答案 0 :(得分:1)

this.statesetState一起使用是一种反模式。因为状态更新是异步的,所以这可能导致争用情况。这是updater function的用例。

几次setState调用将导致批量更新,其中addRelation处于最新更新状态。

一种解决方法是不要批量更新,而要等待状态更新,例如with await

async onAddClick = () => {
    const setStateAsync = updater => new Promise(resolve => this.setState(updater, resolve));

    for (const id of this.state.tempAddList) {
        await setStateAsync(state => ({
            relInfo: {
                ...state.relInfo,
                modId: id
            }
        });
        this.addRelation();
    });
};

一个更好的解决方案是不依赖于副作用的状态更新(addRelation)。 state的目的是在render中使用。如果状态更新不影响视图(仅显示最新的modId更新),则不需要:

 onAddClick = () => {
    let { relInfo } = this.state;
    this.state.tempAddList.forEach((id) => {
        relInfo = { ...relInfo, modId: id };
        this.addRelation(relInfo);
    });

    this.setState({ relInfo });
};

addRelation = (relInfo) => {
    EdmApi.insertModifier(relInfo);
};

如果modId中未使用render,则可以将其从状态中排除。在这种特定情况下,缺少更新程序功能应该不是问题,因为单击处理程序是异步触发的,它们不太可能通过干扰状态更新而导致竞争状态。