简体   繁体   English

有没有比forceUpdate()更好的解决方案

[英]Is there better solution than forceUpdate()

Data ( fragment ) keep by my component state looks like that: 由我的组件状态保存的数据(片段)如下所示:

[
    {
        batchId: 1234,
        ...
        jobRowData: [
            {
                assignmentId: 12345,
                isSelected: false,
                ...
            },
            {
                assignmentId: 12346,
                isSelected: false,
                ...
            }
        ]
    },
    {
        batchId: 1235,
        ...
        jobRowData: [
            {
                assignmentId: 12347,
                isSelected: false,
                ...
            },
            {
                assignmentId: 12348,
                isSelected: false,
                ...
            }
        ]
    }
]

I want to change isSelected and I do it using below method: 我想更改isSelected,并使用以下方法进行操作:

handleIsSelectedChangedJob(selectedIdsData){
    let jobRowData = this.state.batchRowData.find((x) => {return x.batchId === selectedIdsData.batchId}).jobRowData
    let jobRowItemData = jobRowData.find((x) => {return x.assignmentId === selectedIdsData.assignmentId})
    jobRowItemData.isSelected = !jobRowItemData.isSelected // do the update
    // this.setState({batchRowData: [...this.state.batchRowData]}) // this also works instead of this.forceUpdate()
    this.forceUpdate() // how to refresh view according to update 2 lines above ?
}

where argument selectedIdsData could looks like that: 其中参数selectedIdsData可能如下所示:

{assignmentId: 12346, batchId: 1234}

My question is: is there another way of refreshing view than doing this.forceUpdate()? 我的问题是:除了执行this.forceUpdate()之外,还有其他刷新视图的方法吗? Commented line above it also do the job, but it operates on whole state object instead on one changed property. 它上面的带注释的行也可以执行此操作,但是它在整个状态对象上运行,而不是在一个更改的属性上运行。

Definitely! 非也! You should never modify the state directly (by reference) and that's exactly what is happening inside of handleIsSelectedChangedJob . 您永远不应直接(通过引用)修改状态,而这恰恰是handleIsSelectedChangedJob内部发生的handleIsSelectedChangedJob You have to create a new state and call setState : 您必须创建一个新状态并调用setState

handleIsSelectedChangedJob({assignmentId, batchId}) {
  const dataIndex = this.state.batchRowData.findIndex(x => x.batchId === batchId);
  const data = this.state.batchRowData[dataIndex];
  const itemIndex = data.jobRowData.findIndex(x => x.assignmentId === assignmentId);
  const item = data.jobRowData[itemIndex];

  const newItem = {...item, isSelected: !item.isSelected};
  const newData = {
    ...data,
    jobRowData: [].concat(
      data.jobRowData.slice(0, itemIndex),
      newItem,
      data.jobRowData.slice(1 + itemIndex)
    )
  };

  this.setState({
    batchRowData: [].concat(
      batchRowData.slice(0, dataIndex),
      newData,
      batchRowData.slice(1 + dataIndex)
    )
  });
}

As you can see, it's far more code, but now it's not mutating the state, only copying as much as needed. 如您所见,这是更多的代码,但是现在它并没有改变状态,只复制了所需的内容。 Of course, there's plenty of libraries to do it. 当然,有很多库可以做到这一点。 It's still not perfect, as it's not good to read this.state and then call this.setState - using this.state(state => diff) would be safer: 它仍然不是完美的,因为阅读this.state然后调用this.setState并不好-使用this.state(state => diff)会更安全:

handleIsSelectedChangedJob({assignmentId, batchId}) {
  this.setState(state => {
    const dataIndex = state.batchRowData.findIndex(x => x.batchId === batchId);
    const data = state.batchRowData[dataIndex];

    // Same as above...

    return {
      batchRowData: [].concat(
        batchRowData.slice(0, dataIndex),
        newData,
        batchRowData.slice(1 + dataIndex)
      )
    };
  });
}

This should let you do what you desire: 这应该让您做自己想要做的事情:

handleIsSelectedChangedJob(selectedIdsData){
    const _batchRowData = ...this.state.batchRowData;
    const batchIndex = _batchRowData.findIndex((x) => x.batchId === selectedIdsData.batchId);
    const jobIndex = batchIndex < 0 ? -1 : _batchRowData[batchIndex].jobRowData.findIndex((x) => x.assignmentId === selectedIdsData.assignmentId);

    if (batchIndex < 0 || jobIndex <  0) {
        return;
    }

    _batchRowData[batchIndex].jobRowData[jobIndex].isSelected = !batchRowData[batchIndex].jobRowData[jobIndex].isSelected;

    this.setState({ batchRowData: [..._batchRowData] });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM