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.
Related
I have been trying to improve rendering performance by using React.memo on components. It works properly until I use it on every single component from the collection being inserted as children.
I prepared snack HERE
To understand what is going on you need to open the console because there are some logs presented.
You will see WrapperMemo which generally renders Child components (they are also wrapped in some auxiliary components to check something I will explain later).
When you press the first button named SLICE MYNUMBERS you will see that React.memo's isEqual function called isWrapperEqual returns true, but it still does not stop from rerendering Child components.
However neither Wrapper nor all other auxiliary wrapper components (ChildOk) are rendered!
When you click any PRESS ME:[number] button it forces you to re-render other Child components when only one is being modified.
It is worth mentioning that TestCompMemo is never re-rendered when any of the buttons are pressed - which is correct behavior.
1) Is there any explanation for that?
2) Is there a way to use React.memo on every component from collection to render only changed ones (as it is presented in Wrapper component) ?
Is there any explanation for that?
In your snack example, you have a Context.Provider wrapper at the top level of the application.
This is what causes the re-render. This is expected behavior and you can read more about it here: https://github.com/facebook/react/issues/15156#issuecomment-474590693
Is there a way to use React.memo on every component from collection to render only changed ones (as it is presented in Wrapper component) ?
Using React.memo on every component is not recommended. You can run into bugs where components do not re-render and you are adding overhead with all the comparisons.
If you want to optimize the application, you might want to run the profiler and figure out which parts of the app is slowing things down and work from there.
But if you want to prevent unnecessary re-renders, you could move context usage up a few levels and pass the onPress to the child components.
In the attached example codesandbox I have a Map using react-google-maps.
When wrapping the map with <React.StrictMode> it will stop unmounting components.
I see the way react-google-maps unmounts components is usually by setting their map to null using: instance.setMap(null). I don't understand why this behavior should break under StrictMode.
Here's the codesandbox that demonstrates the problem:
https://codesandbox.io/s/jv61orz64y
Thanks!
Uri
I had the same issue and came across your issue on the repo and therefore this question. I have gone into detail on the issue as a comment on your repo issue, but to summarise for SO:
react-google-maps is a little naughty and actually does some rendering-esque work in the constructor of components. In this case, it initialises the google.maps.Marker and calls setMap. That has the effect of putting the marker on the map.
it removes the markers from the map in componentWillUnmount
a component may be constructed but never ends up being mounted, when this happens, componentWillUnmount is never called, as there's nothing mounted to unmount
this means that if the component is constructed but never mounted, and therefore componentWillUnmount is never called, the marker never gets removed from the map
in StrictMode, this exact situation appears to happen, see explanation below:
If you look at my fork of your demo you'll see that in non-strict mode, the Marker proxy (MyMarker) is constructed, mounted, updated, unmounted and then remounted if you load the page zoom in and then zoom out. However, in strict mode two markers get constructed but only one mounted. So what's happening here is not that the marker is never unmounted as you zoom in, but that there are two markers on the map at all times. One that gets "orphaned" on the map by being constructed but never mounted, and the one that is fully under React's control. It truly is being removed and re-added correctly.
I am using react(V0.13.3),flux(V2.0.3)
I have a component that has many inner components.
While the inner component getting updated, the browser is going off. I am unable to scroll click and some time I get a pop up saying:
unresponsive script would you like stop.
I am following all React life cycle methods and implementing the shouldComponentUpdate method.
I think the DOM Diffing is eating so much CPU time and RAM allocated to the browser.
Any idea about why I have this issue and how I could get out of it?
Reactjs can easily go into endless render cycles. Let's say you put a method that pulls Data from the server in componentDidUpdate and it mutates the reducer that is used by a parent Component. Boom. The component tree rerenders. Your shouldComponentUpdate may be useless bc the input is not the same reference. And the server gets hit again. Endless loop.
The solution is to use guards. When you hit your componentDidUpdate (or wherever you hit the backoffice) method for the first time, the method that mutates the reducer should set a kind of IsLoading variable on the reducer. you check this variable to see if you should fire off your mutating request again. This guards against needless rerenders
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.
I want to destroy some component that i have instantiated to release memory.
In my current app almost every view that i instantiate and then release it (remove reference to it) doesn't get garbage collected. I keep no reference to to views. I'm not sure if this memory leak is caused by my app or it's react-native(and react native have some memory leaks problems). is there a way to confidently destroy a view instance ?
React will destroy a component when you don't render it anymore.
or when you omit it from virtual DOM.
const [render, setRender] = useState(true)
<View>
{render
? <HeavyComponent/>
: null
}
<AnotherComponent/>
</View>
I've passed for the same problem time ago, and I discovered that the problem was I wasn't using correctly react.
Why are you instantiating components manually?
Think that one of big main features of reacts is the tree DOM virtual components and if you instantiate a component manually you are, in some way, avoiding it.
Remember that you should use the components in the render function, or functions where components are render and used in the render function. If you have to pass components to another components, you should use the concept of high order component.
I hope I've helped you.