使用Effect hook可以在函數(shù)組件中執(zhí)行副作用
副作用 - 指一段和當(dāng)前執(zhí)行結(jié)果無關(guān)的代碼。
- data fetching
- setting up a subscription
- manually changing the DOM
- logging
useEffect
可以看作是 componentDidMount
, componentDidUpdate
和 componentWillUnmount
的結(jié)合,且useEffect
不會阻塞瀏覽器更新screen。
useEffect 使用方法及執(zhí)行時機:
-
Effects Without Cleanup - 該例子會在每次
render
之后都執(zhí)行effect
- 組建掛載后-
componentDidMount
- 每次
update
后-componentDidUpdate
- 組建掛載后-
useEffect(() => {
document.title = `You clicked ${count} times`;
})
-
Effects With Cleanup - 該例子的
effect
返回了一個函數(shù)- 其他內(nèi)容在每次
render
之后會執(zhí)行 - 返回的函數(shù)內(nèi)容會在組件卸載之前(等同于
componentWillUnmount
)執(zhí)行
- 其他內(nèi)容在每次
useEffect(() => {
const handStatusUpdated = (status) => {
setIsOnline(status.isOnline)
}
ChatAPI.subscribe(friend.id, handStatusUpdated);
return ChatAPI.unsubscribe(friend.id, handStatusUpdated);
})
- 在同一個組件中多次使用
useEffect
- React會按照指定的順序應(yīng)用每個effect -
Skipping Effects - 只有
count
改變才會re-run
該effect
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count])
useEffect(() => {
const handStatusUpdated = (status) => {
setIsOnline(status.isOnline)
}
ChatAPI.subscribe(friend.id, handStatusUpdated);
return ChatAPI.unsubscribe(friend.id, handStatusUpdated);
}, [friend.id])
- 只在
mount
和unmount
時運行的effect
- 依賴項傳入空數(shù)組并返回函數(shù)
useEffect(() => {
// code block mount時執(zhí)行
return () => {
// code block unmount時執(zhí)行
}
}, [])
Hooks 的依賴項
Hooks 提供了讓你監(jiān)聽某個數(shù)據(jù)變化的能力。這個變化可能會觸發(fā)組件的刷新,也可能是去創(chuàng)建一個副作用,又或者是刷新一個緩存。那么定義要監(jiān)聽哪些數(shù)據(jù)變化的機制,其實就是指定 Hooks 的依賴項。
定義依賴項時,需要注意以下三點:
- 依賴項中定義的變量一定是會在回調(diào)函數(shù)中用到的,否則聲明依賴項其實是沒有意義的。
- 依賴項一般是一個常量數(shù)組,而不是一個變量。因為一般在創(chuàng)建
callback
的時候,你其實非常清楚其中要用到哪些依賴項了。 -
React
會使用淺比較來對比依賴項是否發(fā)生了變化,所以要特別注意數(shù)組或者對象類型。
function Sample() {
// 這里在每次組件執(zhí)行時創(chuàng)建了一個新數(shù)組
const todos = [{ text: 'Learn hooks.'}];
useEffect(() => {
console.log('Todos changed.');
}, [todos]);
}
代碼的原意可能是在 todos
變化的時候去產(chǎn)生一些副作用,但是這里的 todos
變量是在函數(shù)內(nèi)創(chuàng)建的,實際上每次都產(chǎn)生了一個新數(shù)組。
useEffect 與三種生命周期方法
useEffect(() => {
// componentDidMount + componentDidUpdate
console.log('這里基本等價于 componentDidMount + componentDidUpdate');
return () => {
// componentWillUnmount
console.log('這里基本等價于 componentWillUnmount');
}
}, [deps])
基本等價于的含義:
- 一方面,
useEffect
(callback) 這個Hook
接收的callback
,只有在依賴項變化時才被執(zhí)行。而傳統(tǒng)的componentDidUpdate
則一定會執(zhí)行。在componentDidUpdate
中,我們通常都需要手動判斷某個狀態(tài)是否發(fā)生變化,然后再執(zhí)行特定的邏輯。 - 另一方面,
callback
返回的函數(shù)(一般用于清理工作)在下一次依賴項發(fā)生變化以及組件銷毀之前執(zhí)行,而傳統(tǒng)的componentWillUnmount
只在組件銷毀時才會執(zhí)行。
useEffect 接收的返回值是一個回調(diào)函數(shù),這個回調(diào)函數(shù)不只是會在組件銷毀時執(zhí)行,而且是每次 Effect 重新執(zhí)行之前都會執(zhí)行,用于清理上一次 Effect 的執(zhí)行結(jié)果。
總結(jié)
學(xué)習(xí)useEffect
要理解什么是副作用以及使用useEffect
傳入不同的參數(shù)時能達到什么效果。雖然 Hooks
在功能上基本可以映射到傳統(tǒng)的 Class
組件的生命周期方法,但是它們卻又不是完全等價的。在實現(xiàn)具體的業(yè)務(wù)功能的時候,都應(yīng)該盡量從 Hooks
的語義角度出發(fā)去思考組件是如何展現(xiàn)和交互的,這樣才能更加順滑地切換到函數(shù)組件的開發(fā)方式。
在函數(shù)組件中你要思考的方式永遠(yuǎn)是:當(dāng)某個狀態(tài)發(fā)生變化時,我要做什么,而不再是在 Class 組件中的某個生命周期方法中我要做什么。