Let's say we have a parent component and multiple functional child components. I want to clearly know if the parent re-renders does the child re-renders or not.
After going through a few articles I came to know there are 3 ways we can detect rerenders. (Let me know if there are more ways.)
1. Put a console.log in the child component.
2. Use Chrome paint flashing option in the settings.
3. Use React dev tool
Do all these ways are correct to know if the component really rerenders? Because it doesn't seem to be work correctly with React.memo.
When I am wrapping the Child component with React.memo it does not print console.log, when the parent component rerenders which is correct. But still with chrome and react dev tools highlights the child component as if it rerendered.
CodeSandbox: https://codesandbox.io/s/bold-cloud-iv0rv
(If we add a new car still the static component is highlighted in green, but as per Memo, it should not rerender.)
Now my doubt, Is paint flashing does not work correctly or React.memo having issues?
Reason
If you use React.memo, you need to use it from parent down to all the child till the end.
Since React.PureComponent share the same feature with React.memo, you can find those explanation in the document as below.
Furthermore, React.PureComponent’s shouldComponentUpdate() skips prop updates for the whole component subtree. Make sure all the children components are also “pure”.
Result
By changing parent component Cars to memo
// Before
export default Cars;
// After
export default React.memo(Cars);
You could find the react-dev-tools in chrome will only show the parent component re-rendered this time as well as no child console.log fired, which is correct. (Compare to previous, all the child also got highlighted)
Before
After
Conclusion
Both console.log and react-dev-tools worked well, you may just need to implement in a proper way following your demand.
Related
I have been struggling with a performance problem in a React (React Native to be exact) app for days. It boils down to this problem:
When a Parent function component has another function component as the Child, the Parent will always re-renders whenever its own parent (GrandParent) re-renders. And this is true even if all components are memoized with React.memo.
It seems to be a fundamental problem for React, because in this common situation, HeavyParent will always re-renders whenever LightGrandParent re-renders, even if neither HeavyParent nor LightChild needs re-rendering. This is obviously causing a massive performance problem for our app.
<LightGrandParent>
<HeavyParent>
<LightChild />
</HeavyParent>
</LightGrandParent>
I can't believe this is how React works. Did I miss anything?
I created a sandbox to show what I mean.
A component re-renders if its state changes, or when its parent re-renders. Re-renders on state changes are normal. The other case sometimes is problematic. In this components tree you pasted
<LightGrandParent>
<HeavyParent>
<LightChild />
</HeavyParent>
</LightGrandParent>
LightGrandParent consumes HeavyParent with props.children, which gives you out of the box optimization, as React won't re-renders HeavyParent if LightGrandParent re-renders because of an internal state change.
Now, if you wanna also control re-renders because of LightGrandParent's parent re-rendering, you could use memo to memoize HeavyParent.
But this won't work because HeavyParent consumes LightChild as children, which is a new refrence on each render, and memo comparing new props with previous to do caching.
The answers #yousumar and a few other folks provided were correct. However, this also means a very surprising phenomenon demonstrated as follows:
I know many developers won't see this as a problem and will just say "hey this is how it works". But I personally think that this at least represents a shortcoming in React's fundamentals, as it violates the principle of least surprise. Also React's core doc should have pointed this out so that developers like me wouldn't get burned.
In our experience, thinking about how the UI should look at any given moment, rather than how to change it over time, eliminates a whole class of bugs.
From React Docs
From my understanding, this means that React only updates what's necessary, rather than destroying and re-constructing the entire DOM tree again. Am I wrong?
Can anyone please help me understand the quoted statement?
Thanks.
From my understanding, this means that React only updates what's necessary, rather than destroying and re-constructing the entire DOM tree again. Am I wrong?
If you want to know the short answer, I have to say it is true, React will update the necessary elements in DOM whenever it needed.
But if you want to know how it's done, and when React will update the DOM and its element I have to it is varying to different several things, like project architecture, using proper methods (proper hooks in functional component eg. useCallback, useMemo, and so on) and so on.
When it truly gets rerender then?
As far as I know, there are two ways React finds out when to rerender the DOM.
Passing elements to ReactDOM.render
Update a state
What is ReactDOM.render?
This will call the render() method from react-dom (Where we usually import it as ReactDOM) and it will render a React element into the DOM in the supplied container and return a reference to the component (or returns null for stateless components). Also if the React element was previously rendered into the container, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React element.
What does state mean?
The state object is where you store property values that belong to the component. So when you got a component and that component has their own specific variables where changing them should affect the DOM you should use it, then whenever state gets changes the component will be updated.
So what I even talk about project architecture and this stuff, when I didn't mention anything about it above?
Let's say we got a project with one parent component and 3 child component just like this:
Component 1
- |- Component 2
- - |- Component 3
- - - |- Component 4
So whenever you a state in Component 4 all of the DOM elements will be get rerendered, why then? Because Component 4 is a child of Component 3 and so on, so when the child state gets change it will force the parent to rerender then the whole DOM will rerender once per state change.
Final Note
So, at last, we should be always considered a good architecture and hierarchy for our project or when it necessarily use built-in methods like useMemo to avoid such a thing.
I am understanding how onPush change detection works in angular. Much of the concept I am cleared. But there is one thing which I am also finding hard to get on Google.
Scenario,
Suppose we have a parent component passing some values to child component and child component have onPush change detection strategy and that child component have a button performing some task not emitting anything to parent.
When we click on that button from child component change detection works from Root component to that parent component and then it seems that there is no reference change in child component so it should not execute the change detection in the child component from where the button was clicked because the reference is not changed.
But it executes there as well.
Here I am confused can anyone help me to make it more clear.
I'm trying to understand better why all my components are re-rendering whenever a route changes in React Router v5. Note, these components are only re-rendering not re-mounting. When I open up the react extension in dev tools and select the Highlight Updates checkbox, I can see all my components get outlined when changing routes, even the components that are at a higher level than the route match:
<Router>
<MyHeader />
<ComponentWithRoutes />
</Router>
In this simple example, I would expect, that changing routes would not re-render the MyHeader component, since nothing changes. However I will still see a highlight with the dev tools. I assume this is expected, since all the examples in the Docs exhibit the same behavior.
My question is two-fold. 1) What is the actual cause of making a component like MyHeader to re-render? It doesn't seem like any props or state are changing. Is it because of the way the Router is using the Context API? The Router is rendering and causing the children to re-render? 2) Why isn't this considered wasteful? It seems like even though the actual DOM isn't changing, React would still have to go through the reconciliation steps in the virtual DOM. Is it just so fast it's doesn't matter? What happens when you start having tons of nested components?
Yup, this is the lay of the land.
Your components will re-render unless they're React.PureComponent, or otherwise define shouldComponentUpdate(), when the parent component is re-rendered.
I have a structure where my Parent Component (Layout)(Presentational Component) will render the DOM which has a child component (Fitme) which will get the scroll height and client to check whether the child is overflowing or not, and reduce/increase the font size.
As React doc says, Parent did mount will be called after all child. So my fitme component gets executed before parent do the paint. It makes child to not work as expected.
Requirement: As I want the Child to be plug-able, i dont want to pass any property in props from parent to notify the child about the mount state.
Edited: Please find the sandbox link.
For the First time (after load), it will not be fitting the text. but if you change the dom, so that it will rerender the component. it will work.
https://codesandbox.io/s/k2051pwl83
Update: I guess this is the issue with the plugin i am using to apply css in js way (aphrodite). not sure about it, but i have raise a ticket in git. and code is update in the sandbox.
Thanks in Advance,
First of all, there is nothing related to React. React does its job to the best. I should have not doubted React.
This issue is related to Aphrodite. It uses asap to to schedule buffer flushing.
As doc says in caveats section,
If you measure DOM elements' dimensions in componentDidMount or componentDidUpdate, you can use setTimeout or flushToStyleTag to ensure all styles are injected.
So i have to add setTimeout in componentDidMount or componentDidUpdate.
Here is the updated CodeSandbox : https://codesandbox.io/s/4364jvm7q9