被父组件移除的子组件仍然获得存储更改事件
Posted
技术标签:
【中文标题】被父组件移除的子组件仍然获得存储更改事件【英文标题】:Child component removed by parent still gets store change event 【发布时间】:2016-02-20 19:15:08 【问题描述】: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。我收到的信息是这样的:
警告:setState(...):只能更新已安装或正在安装的组件。这通常意味着您在未安装的组件上调用了 setState()。这是无操作的。
我发现人们使用 isMounted 来检查组件是否仍在 DOM 中。此方法现已弃用。
我怎样才能以适当的、不断变化的方式解决这个问题?我的组件设计及其相互通信有什么问题?
【问题讨论】:
您可能需要确保在 componentWillUnmount 中禁用相变处理程序 - 我不确定这在您的特定情况下是否有效或足够。 没错,在componentWillUnmount
中,您应该清除/取消订阅您在componentDidMount
中所做的所有事情
是的,我正在删除所有组件中的处理程序,这些组件在componentWillUnmount
中注册了该事件。这没有帮助。当存储更改事件被触发时,所有三个处理程序都会循环通过。在第一个处理程序(PhaseList)中,设置了新阶段。然后调用另外两个处理程序(Phase 和 PhaseHeader),其中已删除的阶段已经消失。
同样的问题***.com/questions/32121231/… 通过将回调方法包装在一个函数中解决。出于某种原因,这确保了您的回调已从 Eventmitter 中删除。
刚刚看到关于 isMounted 弃用的公告。我同意非常好的解释和推理。不过,我仍然没有涵盖边缘情况 - 在 Flux 本身中引用回调(作为正在删除的父组件的子组件中注册的更改处理程序......)facebook.github.io/react/blog/2015/12/16/…
【参考方案1】:
通常您应该只使用生成容器组件的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(/* ... */);
【讨论】:
谢谢丹,这很好,现在就足够了。我即将在当前项目中使用 Redux,以便我可以比较两者。到目前为止,Redux 似乎比我以前使用的“普通”通量模式非常有前途,也更容易。 我在使用 Alt 时遇到了类似的问题,并且使用这种方法(从listen
方法而不是 unlisten
调用取消订阅的函数)解决了它。【参考方案2】:
最自然的方式是在componentDidMount
订阅事件并在componentWillUnmount
取消订阅。
另一件事是,与其监听各种组件级别的更改,我最好只在根组件级别(在您的情况下为 PhasesList)这样做。它将通过 props 传递所有更改,允许 React 确定哪个孩子需要更新。
【讨论】:
将道具向下传递是我想要避免的。我从没有 Flux 的 React 组件开始,然后添加了 Flux 以减少回调和 props 传递。基本上,这个想法是让每个组件从存储中获取它需要的任何数据。这是一个禁止流动的模式吗? 好吧,我认为这与 Flux 无关。它更多的是关于 React、单向数据流和尽可能多地保持组件无状态。将道具向下传递到层次结构 - 这是非常 React 的方式。从 0.14 开始,他们甚至得到了stateless functional components。很简单,很容易测试。您所有的数据管理都应该只交给一些更高级别的根组件。 谢谢格里高利。我仍然需要从 0.13.3 更新,但我喜欢他们引入的无状态组件快捷方式。根据您所说的,我必须根据可重用性标准在哪里传递数据和在哪里监听事件设置一些界限。从一个极端(传下来的所有东西)到另一个极端(到处都是听众)可能在任何一方都不正确。以上是关于被父组件移除的子组件仍然获得存储更改事件的主要内容,如果未能解决你的问题,请参考以下文章
vue---猫眼项目中使用js组件的时候-------loading 加载 无法移除的原因---------
如何将 DOM 附加到 Angular 2 组件并仍然获得封装样式