我在名为SettingsTab
的包装器中呈现React组件TeamView
。它的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();
我想知道的是,应该TeamView#remove
在致电ReactDOM. unmountComponentAtNode(this.el)
之前致电this.el.remove()
?
我可以在网络上找到的示例看起来只有unmountComponentAtNode
才需要调用,如果容器将保留在DOM中;并且新的portals example只是删除了容器,而没有调用unmountComponentAtNode
。
但是,我不确定这是否特别,因为它正在使用门户网站,this post使得调用unmountComponentAtNode
似乎总是好的做法。
答案 0 :(得分:10)
是的,调用unmountComponentAtNode()
很重要,因为如果你不这样做,树下面的任何组件都不会知道它们已被卸载。
用户定义的组件通常在componentDidMount
中执行某些操作,从而在全局环境中创建对树的引用。例如,您可以添加window
事件处理程序(不受React管理),Redux商店订阅,setInterval
调用等。所有这些都很好并且正常,只要这些绑定在componentWillUnmount
中删除。
但是,如果您只是从DOM中删除根但从不调用unmountComponentAtNode
,则React将不知道该树中的组件是否需要卸载。由于他们的componentWillUnmount
永远不会触发,所以这些订阅会保留,并阻止整棵树被垃圾收集。
因此,出于所有实际目的,如果要删除该容器节点,则应始终卸载root。否则你很可能会得到一个内存泄漏 - 如果不是现在,那么稍后当你的一些组件(可能在树的深处,甚至可能来自第三方库)在他们的componentDidMount
中添加订阅时。
答案 1 :(得分:1)
即使您拨打了this.el.remove()
,仍然应该调用unmountComponentAtNode(this.el)
,因为unmountComponentAtNode
会清除其事件处理程序和状态,但remove
方法不会。 / p>
例如,尽管你已经点击删除了div,但仍然可以调用它的click事件处理程序:
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>
答案 2 :(得分:0)
我在#react-internals Discord频道中提出了这个问题并收到了以下回复:
所以,这与@jiangangxiong上面所说的一致:只要我们
我们只需要remove
容器就可以收集组件的事件处理程序和状态垃圾,而不需要调用unmountComponentAtNode
。