Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it necessary to call `unmountComponentAtNode` if the component's container is removed?

Tags:

I render a React component SettingsTab within a wrapper called TeamView. Its API looks something like

class TeamView {
  constructor() {
    this.el = document.createElement('div');
  }

  render() {
    ReactDOM.render(<SettingsTab/>, this.el);
    return this;
  }

  remove() {
    this.el.remove(); 
  }
}

used something like

// to present the team view
const teamView = new TeamView();
document.body.appendChild(teamView.render().el);

// to remove the team view
teamView.remove();

And what I'm wondering is, should TeamView#remove call ReactDOM. unmountComponentAtNode(this.el) before calling this.el.remove()?

The examples I can find around the web make it seem like unmountComponentAtNode only needs to be called if the container is going to remain in the DOM; and the new portals example just removes the container, without calling unmountComponentAtNode.

But, I'm not sure if that's special because it's using a portal, and this post makes it kind of seem like it's always good practice to call unmountComponentAtNode.

like image 996
Jeffrey Wear Avatar asked Sep 29 '17 00:09

Jeffrey Wear


2 Answers

Yes, it is important to call unmountComponentAtNode() because if you don't do this, none of the components below in the tree will know they have been unmounted.

User-defined components often do something in componentDidMount that creates a reference to the tree from the global environment. For example, you may add a window event handler (which isn't managed by React), a Redux store subscription, a setInterval call, etc. All of this is fine and normal as long as these bindings are removed in componentWillUnmount.

However, if you just remove the root from the DOM but never call unmountComponentAtNode, React will have no idea the components in that tree need to be unmounted. Since their componentWillUnmount never fires, those subscriptions stay, and prevent the whole tree from getting garbage collected.

So for all practical purposes you should always unmount the root if you're going to remove that container node. Otherwise you'll most likely get a memory leak—if not now, then later when some of your components (potentially deep in the tree, maybe even from third-party libraries) add subscriptions in their componentDidMount.

like image 148
Dan Abramov Avatar answered Oct 09 '22 21:10

Dan Abramov


Even though you called this.el.remove(), you should still call the unmountComponentAtNode(this.el) because unmountComponentAtNode will clean up its event handlers and state, but the remove method will not.

For example, Eventhough you have clicked to remove the div, you can still call it's click event handlers:

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>
like image 42
JiangangXiong Avatar answered Oct 09 '22 22:10

JiangangXiong