管理不在 DOM 子树中的子组件
Posted
技术标签:
【中文标题】管理不在 DOM 子树中的子组件【英文标题】:Managing subcomponents that are not in DOM subtree 【发布时间】:2014-03-31 21:33:00 【问题描述】:考虑一个组件,它需要管理自己的 DOM 树中不是子组件的子组件,但必须添加到***文档中。
一个典型的例子是自动完成字段,它需要在输入字段下方的浮动菜单中显示自动完成匹配项。浮动菜单必须作为文档主体元素的子元素添加,以逃避树中任何会阻止其显示的“溢出:隐藏”约束。浮动菜单不再使用后需要移除。
在这种情况下,合乎逻辑的方法似乎是将组件挂载到任意 div 中,然后在不再需要时将其卸载。但是,当使用事件触发此类卸载时,这会引入一个有趣的状态流问题。
这是我当前代码的摘录,以说明问题:
componentDidUpdate: function(prevProps, prevState)
if (prevState.matches !== this.state.matches)
if (this._floater)
this._floater.remove();
this._floater = null;
if (this.state.matches.length > 0)
this._floater = Floater.create(
<Floater
parentElement=this.getDOMNode()
open=true>
<SelectableList
items=this.state.matches
limit=10
onSelectionChange=this.handleSelectionChange/>
</Floater>
);
,
handleSelectionChange: function(items)
this.setState(matches: [], selectedItem: items[0]);
,
这里,Floater
是一个通用组件,可以包含任何其他组件;它将自己设置为绝对,定位自己等等。 Floater.create()
是一种创建浮动组件并将其插入到文档中的便捷方法。
Floater.remove()
目前看起来像这样:
remove: function()
var self = this;
if (this.isMounted())
window.setTimeout(function()
React.unmountComponentAtNode(self.getDOMNode().parentNode);
, 10);
,
它使用超时的原因是允许父组件在状态更新后能够远程它。在SelectableList
中选择某些内容会触发父级中的handleSelectionChange
,这将调用remove()
来卸载仍在使用的组件。这很丑陋,虽然它确实有效。
有没有更好、更惯用的方式?
【问题讨论】:
Pete Hunt 提出了一个ReactLayeredComponentMixin
,它将类似于 Float 的 Modal 移动到 Mixin 中,并在组件上公开了 renderLayer
函数,使用它让组件有效地渲染到两个单独的容器:jsfiddle.net/LBAr8 因为它是一个 Mixin 并且使用生命周期方法,你可能会称之为更地道。
【参考方案1】:
只是这个问题的访问者的提示。
从 React v16 开始,有一个特定的功能可以处理这种情况。 它被称为Portal
门户提供了一种一流的方式来将子级呈现到存在于父组件的 DOM 层次结构之外的 DOM 节点中。
【讨论】:
以上是关于管理不在 DOM 子树中的子组件的主要内容,如果未能解决你的问题,请参考以下文章