Maybe a side-effect of the poor equality we have in JS-land.
Actually, stupidcar assessment is completely correct.
> React updates the entire tree internally when anything changes, but actually only changes DOM nodes who's prop or state has changed.
Sorry, but you're mixing up a lot of concepts here!
When you tell react(-dom) to render, it recursively calls all the render() methods of your entire component hierarchy and updates the entire virtual DOM, but only mutates the actual browser's DOM for the parts that are changed.
Yes, there are ways to block a render based on prop staleness using shouldComponentUpdate/PureComponent/React.memo. These are explicit optimisations on top of the default render-everything model.
Props and State play into this story quite a bit differently. When a component-local state changes react only renders that specific component (with everything below it). Props are passed down on every render and are by default not compared for staleness so don't prevent re-renders. Props and DOM updates have nothing to do with each other: props are properties of components, not the DOM! Sure, the DOM can be directly or indirectly be influenced by those props.
> Maybe a side-effect of the poor equality we have in JS-land.
Yes, this is true. A lot of reacts's quirks are a result of JS's poor notion of equality.
God, yes. And I'm amazed everyday to run into senior engineers that do not understand how equality works in JS.
People are also easily confused if they happen to use Redux, because Redux also adds a layer of memoization for you and will not re-render if none of the state (props) or dispatch functions change.
That internal tree update is the root cause of all the problems. During that update, React runs all the javascript in the component, and that of all of it's child components, which then run their child components till the entire tree is done.
Sure, only a small part of the actual DOM will change. But the sheer wastage that happens to update that small part is criminal.
If you have a React Tree that outputs the HTML that is your full page some of your components in that tree will not be re-rendered because the virtual DOM tells you you do not need to re-render them (where we us re-render to mean the React render function is called for that particular part of the tree) but the last render of that component is still saved somewhere and when your whole tree is ready to re-render the HTML of your page (where re-render means actually sending changes to the DOM and causing all the page to re-render)
I don't know enough about how React internals work but I suppose if you have a parent that re-renders but a child does not (React render called again), both will still render (HTML render) at the time of updating the DOM, as I cannot see a logical way that it could not be so.
If a component renders in React, that is, the render function is called, then ALL children's render() function are also called, unless you do specific optimizations such as React.memo.
So the whole tree is rerendered.
When it comes time to apply those changes to the DOM, that is, generating HTML on the page, wherever your render() functions returned the same result as before, the DOM is not touched.
As you said yourself, only children components will be re-rendered. This is relative to the component that had it's state changed (using setState or the useState hook). So not the whole tree rerenders, only the affected component and it's children. And again, when we speak as "re-render", the render() functions of the components are called and then the VDOM diffing happens. That is, even if child components got -rerendered (in react terms), there might not be a DOM update at all (which is the slow, costly operation).
Crawling a large React tree's render stack is also a costly operation. Not as much as DOM manipulation but it is still costly, and React is created in such a way that it requires you to include everything in that stack, even if it never changes. Which is one reason we have Portals.
it may be that way with regular Components, but afaik Pure components are smarter - the idea of Pure components is that react only rerenders the components when the props change. (or something in a hook, if you're using those). though i guess a Pure component is basically equivalent to what you'd get with memo?
Other than that I agree with the gist of your post