React - when do I need to call ReactDOM.unmountComponentAtNode - reactjs

If I render a component into a domNode and then again render another component into the same domNode my understanding is that this is a replace operation rather than an append. The first component will be removed from the dom and from the React Tree in the Virtual representation of the DOM. Therefore I don't need to specifically call ReactDOM.unmountComponentAtNode to clean up the first component.
Is this correct?

That is correct. According to the ReactDOM docs, on ReactDOM.render():
In the future, it may be possible to insert a component to an existing DOM node without overwriting the existing children.
This means that it is not even currently possible to append using ReactDOM.render() - components always get destroyed and replaced.
Generally it is better to avoid the ReactDOM module unless completely necessary. For most React apps, you'll find it is only used to render just the top level wrapper component to the DOM.

Related

Which DOM does react component render function refers to? real-dom or vitual-dom?

I have read lots of articles and believe this question is not the duplicated one.
According to What is the role of the render() function inside react component?
render function is part of the react component lifecyle where ReactDOM
is the class object which exposes a method called render which is used
to render the React JSX content into your DOM.
and I also read many articles which explain how the react virtual dom works, which uses diff process before render its node to the real-dom.
All the articles (at least what I've read) mention that render() reflects dom
I wonder if that dom is real-dom or virtual-dom
Actually I am having some trouble understanding componentDidUpdate() which is immediately invoked after render(), realizing my lack of understanding of component's render function
appreciate for your help
react interact with Virtual DOM.To apply updates/changes to real DOM, the Virtual DOM core feature comes into play, the reconciliation algorithm.
It's job is to come up with the most optimized solution to resolve the difference between previous and current Virtual DOM state. And then apply the new Virtual DOM to the real DOM.
this article will help to understand virtual DOM in depth https://medium.com/#gethylgeorge/how-virtual-dom-and-diffing-works-in-react-6fc805f9f84e
componentDidUpdate is the last opportunity to react to change in props, during the given cycle of the react component's life.
It is the last opportunity because it has access to prevProps.
and BTW right after the render - getSnapshotBeforeUpdate(prevProps, prevState) is called and only then componentDidUpdate.
According to react doc -
getSnapshotBeforeUpdate() is invoked right before the most recently rendered output is committed to e.g. the DOM. It enables your component to capture some information from the DOM (e.g. scroll position) before it is potentially changed. Any value returned by this lifecycle will be passed as a parameter to componentDidUpdate().
So I assume that render method refers to the real DOM.

REACT using Ref

is it true, the purpose of Ref is replacing document.getElementById??
Once i apply react, i should not use document.getElementById to access DOM to get data?
i found some article said that we can apply the this.refs to access the DOM
<input ref="test" value="option" id="option4"/>
console.log(this.refs.test);
But it can only run within the method within the component,
what if i want show the input value in console (developer Tools)?
It is true in a way, because react uses its virtual dom and diffing algorithm to watch changes and reflect in dom. If you use direct api to access dom. react could not access it in its virtual dom.
Thats why they have an unique id or keys just like in DOM to manipulate elements (components) as node.
If you see in confirm-alert components used in npm packages, they will create an element and render it as an element by using ReactDOM. As soon the toaster is finished it is not removed directly from the DOM.
First it is made to be find from the reactVirtualDom by using api findDomNode at https://reactjs.org/docs/react-dom.html#finddomnode
then it is unmounted using unmountComponentAtNode.
https://reactjs.org/docs/react-dom.html#unmountcomponentatnode
For example: https://github.com/GA-MO/react-confirm-alert/blob/master/src/index.js
So, refs are used to overcome direct DOM manipulation and changes that affect or effects the react rendering process.

Any need to manually remove an event listener that was manually added to an element in a React component?

Consider the following scenario:
I have a piece of (safe) HTML that I import in a js module and add to a React component using the dangerouslySetInnerHtml prop.
I then use the escape hatch that refs provide to access the mounted React component.
let foo = this.refs.foo;
And add an event listener to a DOM element inside that mounted component
foo.querySelector('a').addEventListener('click', callback, true);
Question Will React remove this event listener automatically when the component is unmounted, or do I need to do this manually in componentWillUnmount? I can't imagine why React wouldn't remove it along with the DOM node it was added to, but I couldn't find any reference to support or contradict my intuition.
What do you think?
Modern browsers will collect event handlers of removed DOM elements.
But if you hold a reference of that DOM element somewhere, the event handlers can't be collected by a browser and cause memory leak.
So the safest way is to remove all the event handlers in your componentWillUnmount.

Calling ReactDOM.render repeatedly and memory leaks

On this React page it says that you manually need to invoke unmountComponentAtNode because:
This is important and often forgotten. Forgetting to call
unmountComponentAtNode will cause your app to leak memory.
I have an app that is repeadedly passing properties to a root component and calling ReactDOM.render. Do I need to call unmountComponentAtNode for the container element in order to prevent a "memory leak", whatever that means?
I've tried doing this and noticed that it results in re-mounting of all child components, while calling ReactDOM.render without unmountComponentAtNode seems to do a diff and doesn't mount any child components again.
So is it okay to call ReactDOM.render without unmountComponentAtNode? Will this cause any memory leaks? On this page it says under ReactDOM.render:
If the ReactElement was previously rendered into container, this will
perform an update on it and only mutate the DOM as necessary to
reflect the latest React component.
ReactDOM.render() controls the contents of the container node you pass
in. Any existing DOM elements inside are replaced when first called.
Later calls use React’s DOM diffing algorithm for efficient updates.
It doesn't mention any side effects.
EDIT:
I did some simple tasks using Chrome where I called ReactDOM.render with 1 simple component 1 million times using with/without unmountComponentAtNode. The page took around 5 seconds to complete without it and froze and consumed 10x (I stopped it because it froze my window) according to Chrome task manager. So not sure what do they mean by preventing memory leaks using unmountComponentAtNode when the evidence shows that using it may CAUSE them.
ReactDOM.render can be used to update a top-level component with new props. That's a perfectly acceptable use for it. What unmountComponentAtNode is for is when the component's top-level DOM node is removed from the DOM. Otherwise the DOM node will be kept around due to React's reference to it, thus the memory leak.

React.js: Bind to Existing Elements

In Backbone.js, you can specify a view's element by using the el property or by calling view.setElement().
Is there an equivalent way of hooking up a React.js component to an existing DOM element?
I'm not overly familiar with Backbone, but to hook a React component into the DOM you use the renderComponent function. The first arg is the component, and the second is a DOM element:
React.renderComponent(<SampleComponent />, document.getElementById('app'));
Updated per the context given in the comments:
React hooks up to an element by replacing its contents, but not the element itself. You can call renderComponent() more than once on that element and it will run the same diff algorithm each time. This is handy if you want to pass in different props, pre-render on the server, or render a different component entirely. The same process is used to update the actual DOM each time, just like if you were to use setState() within the component itself.

Resources