如果组件的容器被移除,是否需要调用 `unmountComponentAtNode`?
Is it necessary to call `unmountComponentAtNode` if the component's container is removed?
我在名为 TeamView
的包装器中渲染了一个 React 组件 SettingsTab
。它的 API 看起来像
class TeamView {
constructor() {
this.el = document.createElement('div');
}
render() {
ReactDOM.render(<SettingsTab/>, this.el);
return this;
}
remove() {
this.el.remove();
}
}
使用类似
的东西
// to present the team view
const teamView = new TeamView();
document.body.appendChild(teamView.render().el);
// to remove the team view
teamView.remove();
我想知道的是,应该在调用 this.el.remove()
之前 TeamView#remove
调用 ReactDOM. unmountComponentAtNode(this.el)
吗?
我可以在网上找到的示例表明 unmountComponentAtNode
仅当容器要保留在 DOM 中时才需要调用;并且新的 portals example 只是删除容器,而不调用 unmountComponentAtNode
.
但是,我不确定这是否特别,因为它使用的是门户,而且 this post 让人觉得调用 unmountComponentAtNode
.
似乎总是一种好习惯
即使您调用了 this.el.remove()
,您仍应调用 unmountComponentAtNode(this.el)
,因为 unmountComponentAtNode
将清理其事件处理程序和状态,但 remove
方法不会.
例如,即使您点击删除了 div,您仍然可以调用它的点击事件处理程序:
var tap = document.querySelector('.tap');
var other = document.querySelector('.other');
tap.addEventListener('click', function(e) {
console.log(tap.getAttribute('data-name') + ' has been clicked');
tap.remove();
});
other.addEventListener('click', function(e) {
tap.click();
});
<div class="tap" data-name="tap">First Click me to remove me</div>
<div class="other">Then Click me </div>
我在 #react-internals Discord 频道中提出了这个问题并收到了以下回复:
所以,这符合@jiangangxiong上面说的:只要我们
- 不要保留我们自己对组件 DOM 元素的引用
- 也不在 React 之外附加事件处理程序
- 并且只需要支持现代浏览器
我们应该只需要 remove
容器来收集组件的事件处理程序和状态垃圾,不需要调用 unmountComponentAtNode
.
是的,调用 unmountComponentAtNode()
很重要,因为如果您不这样做,树中下面的 none 组件将知道它们已被卸载。
用户定义的组件通常在 componentDidMount
中做一些事情,从全局环境中创建对树的引用。例如,您可以添加一个 window
事件处理程序(不由 React 管理)、一个 Redux store 订阅、一个 setInterval
调用等。只要这些都可以正常进行componentWillUnmount
.
中删除了绑定
然而,如果你只是从 DOM 中删除根但从未调用 unmountComponentAtNode
,React 将不知道该树中的组件需要卸载。由于它们的 componentWillUnmount
永远不会触发,这些订阅会保留下来,并防止整个树被垃圾收集。
因此,出于所有实际目的,如果您要删除该容器节点,您应该始终卸载根目录。否则你很可能会发生内存泄漏——如果不是现在,那么稍后当你的一些组件(可能在树的深处,甚至可能来自第三方库)在它们的 componentDidMount
.[=18 中添加订阅时=]
我在名为 TeamView
的包装器中渲染了一个 React 组件 SettingsTab
。它的 API 看起来像
class TeamView {
constructor() {
this.el = document.createElement('div');
}
render() {
ReactDOM.render(<SettingsTab/>, this.el);
return this;
}
remove() {
this.el.remove();
}
}
使用类似
的东西// to present the team view
const teamView = new TeamView();
document.body.appendChild(teamView.render().el);
// to remove the team view
teamView.remove();
我想知道的是,应该在调用 this.el.remove()
之前 TeamView#remove
调用 ReactDOM. unmountComponentAtNode(this.el)
吗?
我可以在网上找到的示例表明 unmountComponentAtNode
仅当容器要保留在 DOM 中时才需要调用;并且新的 portals example 只是删除容器,而不调用 unmountComponentAtNode
.
但是,我不确定这是否特别,因为它使用的是门户,而且 this post 让人觉得调用 unmountComponentAtNode
.
即使您调用了 this.el.remove()
,您仍应调用 unmountComponentAtNode(this.el)
,因为 unmountComponentAtNode
将清理其事件处理程序和状态,但 remove
方法不会.
例如,即使您点击删除了 div,您仍然可以调用它的点击事件处理程序:
var tap = document.querySelector('.tap');
var other = document.querySelector('.other');
tap.addEventListener('click', function(e) {
console.log(tap.getAttribute('data-name') + ' has been clicked');
tap.remove();
});
other.addEventListener('click', function(e) {
tap.click();
});
<div class="tap" data-name="tap">First Click me to remove me</div>
<div class="other">Then Click me </div>
我在 #react-internals Discord 频道中提出了这个问题并收到了以下回复:
所以,这符合@jiangangxiong上面说的:只要我们
- 不要保留我们自己对组件 DOM 元素的引用
- 也不在 React 之外附加事件处理程序
- 并且只需要支持现代浏览器
我们应该只需要 remove
容器来收集组件的事件处理程序和状态垃圾,不需要调用 unmountComponentAtNode
.
是的,调用 unmountComponentAtNode()
很重要,因为如果您不这样做,树中下面的 none 组件将知道它们已被卸载。
用户定义的组件通常在 componentDidMount
中做一些事情,从全局环境中创建对树的引用。例如,您可以添加一个 window
事件处理程序(不由 React 管理)、一个 Redux store 订阅、一个 setInterval
调用等。只要这些都可以正常进行componentWillUnmount
.
然而,如果你只是从 DOM 中删除根但从未调用 unmountComponentAtNode
,React 将不知道该树中的组件需要卸载。由于它们的 componentWillUnmount
永远不会触发,这些订阅会保留下来,并防止整个树被垃圾收集。
因此,出于所有实际目的,如果您要删除该容器节点,您应该始终卸载根目录。否则你很可能会发生内存泄漏——如果不是现在,那么稍后当你的一些组件(可能在树的深处,甚至可能来自第三方库)在它们的 componentDidMount
.[=18 中添加订阅时=]