First of all, by "re-render", here it means either
- the
render()
method of any class component is called, OR - the function of the function component is called.
Let's called the element in the actual DOM changing a "refresh", to distinguish it from "re-render".
Is the rule of "re-render" as simple as:
When any state of a component is changed, then the component and all the subtree down from this component is re-rendered
and that's it? For example:
function A() {
console.log("Component A re-render");
return <div>Component A says Hello World</div>;
}
function App() {
const [counter, setCounter] = React.useState(0);
console.log("Component App re-render");
function increaseCount() {
setCounter(c => c + 1);
}
return (
<div>
{counter}
<button onClick={increaseCount} >Increment</button>
<A />
</div>
)
}
ReactDOM.render(<App />, document.querySelector("#root"));
<script src="https://unpkg.com/react@16.12.0/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>
Component A is so simple: it doesn't even take any props and is just outputting static text, yet it is still called every time (by looking at the console.log()
output).
But even though it is "re-rendered", the actual DOM element is not "refreshed", as seen in Google Chrome's Inspect Element that the DOM element is not flashing for Component A, but is only flashing for the counter number.
So is this how it works?
- Whenever any state of a component is changed, that component and the whole subtree will be "re-rendered".
- But ReactJS will "reconcile" the content of the "Virtual DOM" that it built using those JSX with the content of the actual DOM, and if the content is different, "refresh the actual DOM".
But having said that, it seems ReactJS doesn't actually reconcile with the actual DOM, but reconcile with probably the "previous virtual DOM". Why? Because if I use a setTimeout()
to change the actual DOM of Component A to some other content after 3 seconds, and click the button, ReactJS doesn't change the content of Component A back to "Hello World". Example:
function A() {
console.log("Component A re-render");
return <div id="foo">Component A says Hello World</div>;
}
function App() {
const [counter, setCounter] = React.useState(0);
console.log("Component App re-render");
function increaseCount() {
setCounter(c => c + 1);
}
return (
<div>
{counter}
<button onClick={increaseCount} >Increment</button>
<A />
</div>
)
}
ReactDOM.render(<App />, document.querySelector("#root"));
setTimeout(function() {
document.querySelector("#foo").innerText = "hi"
}, 3000);
<script src="https://unpkg.com/react@16.12.0/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>