如果组件的容器被移除,是否需要调用 `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 中添加订阅时=]