1. Principle#
First, the render
function has two forms in react
:
In class components, it refers to the render
method:
class Foo extends React.Component {
render() {
return <h1> Foo </h1>;
}
}
In function components, it refers to the function component itself:
function Foo() {
return <h1> Foo </h1>;
}
In the render
function, we write jsx
, which is compiled into the familiar js
format using babel
, as follows:
return (
<div className='cn'>
<Header> hello </Header>
<div> start </div>
Right Reserve
</div>
)
After babel
compilation:
return (
React.createElement(
'div',
{
className : 'cn'
},
React.createElement(
Header,
null,
'hello'
),
React.createElement(
'div',
null,
'start'
),
'Right Reserve'
)
)
From the name, the createElement
method is used for creating elements.
In react
, these elements are nodes in the virtual DOM tree, which accept three parameters:
- type: tag
- attributes: tag attributes, if none, it is null
- children: tag's child nodes
These virtual DOM trees are eventually rendered into real DOM.
During the render
process, React
compares the tree returned by the newly called render
function with the old version of the tree. This step is a necessary step to determine how to update the DOM
. Then it performs a diff
comparison and updates the DOM
tree.
2. Trigger Timing#
The execution timing of render
can be divided into two parts:
- Class component calls
setState
to modify state
class Foo extends React.Component {
state = { count: 0 };
increment = () => {
const { count } = this.state;
const newCount = count < 10 ? count + 1 : count;
this.setState({ count: newCount });
};
render() {
const { count } = this.state;
console.log("Foo render");
return (
<div>
<h1> {count} </h1>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
When the button is clicked, the setState
method is called, and regardless of whether count
has changed, Foo render
will be output to the console, indicating that render
has been executed.
- Function component modifies state using
useState
hook
function Foo() {
const [count, setCount] = useState(0);
function increment() {
const newCount = count < 10 ? count + 1 : count;
setCount(newCount);
}
console.log("Foo render");
return (
<div>
<h1> {count} </h1>
<button onClick={increment}>Increment</button>
</div>
);
}
The function component updates data using the useState
form. If the value of the array does not change, render
will not be triggered.
- Class component re-renders
class App extends React.Component {
state = { name: "App" };
render() {
return (
<div className="App">
<Foo />
<button onClick={() => this.setState({ name: "App" })}>
Change name
</button>
</div>
);
}
}
function Foo() {
console.log("Foo render");
return (
<div>
<h1> Foo </h1>
</div>
);
}
Whenever the Change name
button inside the App
component is clicked, regardless of the specific implementation of Foo
, it will be re-rendered.
- Function component re-renders
function App(){
const [name,setName] = useState('App')
return (
<div className="App">
<Foo />
<button onClick={() => setName("aaa")}>
{ name }
</button>
</div>
)
}
function Foo() {
console.log("Foo render");
return (
<div>
<h1> Foo </h1>
</div>
);
}
It can be observed that when using useState
to update the state, Foo render
is only triggered once, and it does not trigger Foo render
afterwards.
3. Summary#
The render
function can write JSX
inside it, which is converted into the createElement
form to generate a virtual DOM, which is eventually converted into a real DOM.
In React
, whenever a class component executes the setState
method, the render
function is always triggered, while a function component using useState
to change the state does not necessarily trigger a re-render.
If the props
of a component change, it does not necessarily trigger the execution of the render
function. However, if the value of props
comes from the state
of a parent or ancestor component, in this case, if the state
of the parent or ancestor component changes, it will cause the child component to be re-rendered.
Therefore, once setState
is executed, the render
method is executed. useState
determines whether to execute the render
method based on whether the current value has changed. Once the parent component is rendered, the child component will also be rendered.