被父组件移除的子组件仍会获取存储更改事件

Child component removed by parent still gets store change event

tl;dr:与 mridgway 在此处描述的问题相同:isMounted is not enough to know if you can setState

我有一个这样的组件层次结构:

PhasesList
- Phase
  - PhaseHeader
- Phase
  - PhaseHeader

还有一个 PhaseStore,它维护一个阶段列表及其详细信息。

在所有三个组件中,我侦听 PhaseStore 更改并根据更改更新状态(重新渲染)。例如,如果用户更改 PhaseHeader 中的阶段名称,我会触发操作、存储更新并发出更改事件。该更改事件将传播到以实际名称值呈现的 PhaseList、Phase 和 PhaseHeader。

有一个有问题的案例,我可以删除一个阶段。此操作在 PhaseStore 中处理,其中从列表中删除阶段并发出更改事件(与其他情况一样)。此事件由所有组件处理,从上到下(因为所有组件都监听存储更改)。

因此,在 PhasesList 中,呈现了一组新的阶段,而没有删除一个阶段。但是,删除的阶段组件仍然接收更改事件,PhaseHeader 也是如此。

在这两个组件中,在相变处理程序中我使用了 setState。我收到的消息是这样的:

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op.

我发现人们使用 isMounted 来检查组件是否仍在 DOM 中。此方法现已弃用。

我怎样才能以适当的、通量的方式解决这个问题?我的组件设计及其相互通信有什么问题?

最自然的方式是在componentDidMount订阅事件,在componentWillUnmount取消订阅。

另一件事是,与其监听各种组件级别的更改,我最好只在根组件级别上执行此操作,在您的情况下是 PhasesList。它将通过 props 向下传递所有更改,允许 React 确定哪个子项需要更新。

通常你应该只使用生成容器组件的React Redux。它已经过大量优化,比使用 setState() 的手动代码运行得更快,并且特别针对您提到的情况提供了保护。

否则你可以这样做:

componentDidMount() {
  this.unsubscribe = store.subscribe(this.handleChange.bind(this));
}

componentWillUnmount() {
  this.unsubscribe();
  this.unsubscribe = null;
}

handleChange() {
  if (!this.unsubscribe) {
    return;
  }

  this.setState(/* ... */);
}