一、原理#
首先,render
函数在react
中有两种形式:
在类组件中,指的是render
方法:
class Foo extends React.Component {
render() {
return <h1> Foo </h1>;
}
}
在函数组件中,指的是函数组件本身:
function Foo() {
return <h1> Foo </h1>;
}
在render
中,我们会编写jsx
,jsx
通过babel
编译后就会轉化成我們熟悉的js
格式,如下:
return (
<div className='cn'>
<Header> hello </Header>
<div> start </div>
Right Reserve
</div>
)
babel
編譯後:
return (
React.createElement(
'div',
{
className : 'cn'
},
React.createElement(
Header,
null,
'hello'
),
React.createElement(
'div',
null,
'start'
),
'Right Reserve'
)
)
從名字上來看,createElement
方法用來元素的
在react
中,這個元素就是虛擬DOM
樹的節點,接收三個參數:
-
type:標籤
-
attributes:標籤屬性,若無則為 null
-
children:標籤的子節點
這些虛擬DOM
樹最終會渲染成真實DOM
在render
過程中,React
將新調用的 render
函數返回的樹與舊版本的樹進行比較,這一步是決定如何更新 DOM
的必要步驟,然後進行 diff
比較,更新 DOM
樹
二、觸發時機#
render
的執行時機主要分成了兩部分:
- 類組件調用 setState 修改狀態
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>
);
}
}
點擊按鈕,則調用setState
方法,無論count
發生變化辯護,控制台都會輸出Foo render
,證明render
執行了
- 函數組件通過
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>
);
}
函數組件通過useState
這種形式更新數據,當數組的值不發生改變了,就不會觸發render
- 類組件重新渲染
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>
);
}
只要點擊了 App
組件內的 Change name
按鈕,不管 Foo
具體實現是什麼,都會被重新render
渲染
- 函數組件重新渲染
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>
);
}
可以發現,使用useState
來更新狀態的時候,只有首次會觸發Foo render
,後面並不會導致Foo render
三、總結#
render
函數裡面可以編寫JSX
,轉化成createElement
這種形式,用於生成虛擬DOM
,最終轉化成真實DOM
在 React
中,類組件只要執行了 setState
方法,就一定會觸發 render
函數執行,函數組件使用useState
更改狀態不一定導致重新render
組件的 props
改變了,不一定觸發 render
函數的執行,但是如果 props
的值來自於父組件或者祖先組件的 state
在這種情況下,父組件或者祖先組件的 state
發生了改變,就會導致子組件的重新渲染
所以,一旦執行了setState
就會執行render
方法,useState
會判斷當前值有無發生改變確定是否執行render
方法,一旦父組件發生渲染,子組件也會渲染