My current understanding is that a component mounts onto the DOM when it is needed to be seen or when the route requires that component. It will also render its child components. Does this mean that a component will be unmounted when you visit a route that doesn't have that component or whenever you visit any page that doesn't show the element that component produces? Thus, a component will need to be remounted every time it shows up on the DOM (outside of prop and state changes), correct?
During the VirtualDOM Reconciliation if a component existed but no longer will, the component is considered unmounted and given a chance to clean up (via componentWillUnmount).
The reverse is true, during the reconciliation, if a component didn't exist, but now does, the component is considered ready to mount, and given a chance to prep itself (constructor / componentWillMount)
When tearing down a tree, old DOM nodes are destroyed. Component
instances receive componentWillUnmount(). When building up a new tree,
new DOM nodes are inserted into the DOM. Component instances receive
componentWillMount() and then componentDidMount(). Any state
associated with the old tree is lost.
https://facebook.github.io/react/docs/reconciliation.html
That particular page is well worth a read if you haven't already. It also explains why key is pretty important for repeated elements.
Component will be mounted on DOM only when it needs to be rendered. If you change the route or refresh the page or you want to render your component on specific events (eg onClick show/hide the component) then componentWillUnmount() will be called and component will be removed from DOM
Simply put, when a component has mounted, componentDidMount() is called, when the component is about to unmount, componentWillUnmount() is called. During re-rendering, if the component is neither to be mounted nor unmounted, neither of the aforementioned methods will be called. Instead, simply the changes made to the code of the component will be updated.
Please remember that most React apps are Single Page Apps which means they only update the existing page, they don't create any new page like page1.html, page2.html. What happens is that React unmounts unnecessary components from page1 and mounts necessary components described in page2 such that it looks like page2. But it doesn't really "leave page1.html" and take you to a whole new page called page2.html. All it does is simply pop and push components in one canvas or page. In other words, React "brings" page2 into page1. But the canvas remains the same(page1).
So, the answer to your question is, yes, a component will unmount and remount when its removed or added to the page.
I would say a component mount onto the DOM only if it's used via another component, including a Router component. Don't think of routers as special elements/things in React. They're like other components and they do a matching between current URL and the patterns they have to decide which component should be rendered via the render() function of Router. Whenever there is a change of URL, the router picks the new component to render and does rendering via render() function.
Related
Let's say I've triggered an update of a single React component & as we know by default it will trigger the update of all it's children components.
BUT
How does it work in combination with browser's reflow/repaint ?
How does the whole process look like (step by step) after we trigger a single React-component's update?
By default, the child components would be updated as well, however, that only happens in the virtualDOM, and not the actual DOM.
Changes are made to the virtualDOM, React then checks to see which DOM elements/components are changed/updated, and only those are updated in the actual DOM, it's part of the reason why your React app is fast.
You can refer to this thread for more information, though I think they are more so on class component, not functional component.
If I have two parent components that render conditionally based on a flag, and if both parent components share a a child component, that really never changes, how can I avoid re-rendering that child component?
Codesandbox.
As you can see, I even tried to use React.memo, but rendered side prints regardless.
The child component, <Side />, is rendering every time because: you're rendering this child component as a child component of either <SecondaryTemplate /> or <PrimaryTemplate />. While you programmatically (switching view) render anyone of this, other immediately gets unmounted completely from the DOM, as <Side /> is a child of the component just got unmounted, it no longer exists in the DOM, and when another one renders, it renders its child component because React algorithm run on virtual DOM knows in no way about the that exists before, hence it has no meaning to expect that it will reder only once whether it changes or not.
To understand this you can look at this:
https://codesandbox.io/s/vigorous-khayyam-14ls0?file=/src/MainComponent.js
Where I forked your code, look at the console, you will see that when you switch the view one component gets unmounted (and hence its child <Side /> too).
I have a base class in React which is getting extended by child classes:
export default class extends Base {
...
}
Now, in order to efficiently subscribe to events and automatically unsubscribe by the time the component is getting unmounted, I am using a method called subscribe and method called unsubscribe in the Base class (which is the parent) to handle this.
Now everything is working good, until I move from the same page, to the same page, but with different ID in props.
In such a case, what happening is that the joining component did mount functions are getting executed BEFORE the leaving component functions. For example see this console:
The first mounted to console is the first page that was loaded.
Then the second mounted to is the new component that is getting joined.
And the last unmounted from is getting executed from the first component that is leaving.
In such a case, React subscribes to events in the joining component and then just unsubscribe them, because of the unmount of the OLD component.
I need to be sure that the old component is clearing all of its subscribes and then initiate the new component. OR - I need to disable unsubscribing for events if the new component is the same component but with different props.
How to fix this issue?
Consider the following example:
class GridContainer extends React.Component {
...
render (){
return <div>
<Pagination portalId="portal-id"></>
<Grid ...>
</div>
}
}
class Grid extends React.Component {
...
render (){
return <div>
<div id="portal-id"></>
<table ...>
</div>
}
}
class Pagination extends React.Component {
...
render (){
return return ReactDOM.createPortal(<div>Paginator DOM...</div>, document.getElementById(this.props.portalId));
}
}
Is it safe to render a portal inside other components DOM? I've tested it and it works, but I don't know if this is reliable. The Portals doc mention that you can render a portal in a DOM node but nothing about components DOM.
Why is this different (speculating here)? while updating the portal parent component, in the reconciliation process the diff might find the inconsistency and remove the portal node.
From my testing, the above doesn't happen but I don't know if I can assume that react handles it. So here comes the Q:
Is it safe to render a portal into another component DOM?
Is it safe? Sure, but it probably won't work the way you expect.
First off, you can totally dump dom inside a div that React created.
I've met several React programmers who would contest this fact, but Reacts design expects and accounts for editing dom directly when necessary. If they didn't, there would be no componentDidUpdate or React refs.
This documentation on integration with other libraries is probably the most relevant.
Here's the scoop:
React won't touch the internals of a rendered div, assuming it's always empty at the end of render. It will only:
Create new elements, which is irrelevant here as long as you leave it empty.
Update existing elements that were originally created by react.
Delete elements that were originally created by react.
So just create that empty div and leave it alone in render and React won't mess with it.
Here's the rub; React guarantees nothing about the timing of the renders.
This means that you have no idea if the element will actually be there when Pagination renders, causing the query to fail and the portal to not display. componentDidUpdate only works because React specifically runs it after the dom is updated. But render is run before the dom is updated. So if Pagination is rendered in the same sweep as Grid that div is likely not mounted yet.
Now the infamous stack overflow Just-Don't-Do-That answer:
Just don't do that. The purpose of portal is to let you render outside the React container while keeping your components inside of Reacts render tree. If you're rendering inside React render tree anyways why don't you just render the components there? (if that statement is confusing I blame you)
The Portals doc mention that you can render a portal in a DOM node but nothing about components DOM
This isn't mentioned because this is special case of general rule; DOM shouldn't be accessed directly in React if there are more idiomatic ways.
A lot of memory leaks occur in DOM. In case a component that hosts a portal (Grid) is re-rendered and portal component (Pagination) is not, this will result in detached DOM, i.e. memory leak.
An element where a portal is attached may not even exist at the time when portal component renders.
I want to know, what are events, that cause React component to re-render.
I couldn't find full list anywhere, it'd be great if someone writes the list of events, that cause React component to re-render.
I always find the following reference website helpful.
http://reactcheatsheet.com/
Filter by lifecycle events, and you can see the places where setState will trigger a rerender.
__
Update: you now have to filter by "misc"
React component is re-rendered when setState() is called or when props change. You can also force re-render with forceUpdate()
https://reactjs.org/docs/react-component.html#forceupdate
By default, when your component's state or props change, your
component will re-render. However, if these change implicitly (eg:
data deep within an object changes without changing the object itself)
or if your render() method depends on some other data, you can tell
React that it needs to re-run render() by calling forceUpdate().