useEffect的含義:副作用鉤子棚唆,用于處理組件中的副作用泳猬,用來(lái)取代生命周期函數(shù)。所謂的"副作用"就是指的是組件中狀態(tài)或生命周期改變時(shí)在useEffect可監(jiān)聽(tīng)到前计。
如果熟悉class組件中生命周期方法均澳,可以將useEffect視作coponentDidMount恨溜、componentDidUpdate和componentWillUnmount的組合體。
useEffect使用的幾種方式找前,根據(jù)第二個(gè)參數(shù)的情況而定
- 無(wú)此參數(shù):組件的任何更新糟袁,該 useEffect 對(duì)應(yīng)的返回函數(shù)和函數(shù)都執(zhí)行
- 為空數(shù)組:只在componentDidMount執(zhí)行一次,不監(jiān)聽(tīng)組件的更新躺盛,
- 數(shù)組中有具體依賴:對(duì)應(yīng)的依賴數(shù)據(jù)项戴,有變化的時(shí)候,才會(huì)執(zhí)行(初始不會(huì)執(zhí)行)
清除 effect
通常槽惫,組件卸載時(shí)需要清除 effect 創(chuàng)建的諸如訂閱或計(jì)時(shí)器 ID 等資源周叮。要實(shí)現(xiàn)這一點(diǎn),useEffect 函數(shù)需返回一個(gè)清除函數(shù)界斜。以下就是一個(gè)事件綁定的例子:
import { useState, useEffect } from "react";
import * as ReactDOM from "react-dom";
function App() {
const [position, setPosition] = useState({x:0, y: 0})
useEffect(()=>{
console.log('點(diǎn)擊了b')
const mouseClickHandle = (e) =>{
console.log('點(diǎn)擊了c')
setPosition({
x: e.clientX,
y: e.clientY
})
}
document.addEventListener('click', mouseClickHandle)
// return ()=>{
// console.log('點(diǎn)擊了d')
// document.removeEventListener('click', mouseClickHandle)
// }
})
console.log('點(diǎn)擊了a')
return (
<>
<p>
X:{position.x}, Y: {position.y}
</p>
</>
)
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
執(zhí)行點(diǎn)擊事件仿耽,可以看到打印結(jié)果如下:
可以看到,當(dāng)我第三次點(diǎn)擊的時(shí)候锄蹂,打印結(jié)果顯示click事件被執(zhí)行了兩次氓仲,在這個(gè)示例中水慨,意味著組件的每一次更新都會(huì)創(chuàng)建新的事件綁定得糜,這很顯然是不被允許的。
這個(gè)時(shí)候就需要使用清除函數(shù)晰洒,清除函數(shù)會(huì)在組件卸載前執(zhí)行朝抖。另外,如果組件多次渲染(通常如此)谍珊,則在執(zhí)行下一個(gè) effect 之前治宣,上一個(gè) effect 就已被清除。
useEffect允許返回一個(gè)函數(shù)來(lái)解決上述問(wèn)題:
useEffect(()=>{
console.log('點(diǎn)擊了b')
const mouseClickHandle = (e) =>{
console.log('點(diǎn)擊了c')
setPosition({
x: e.clientX,
y: e.clientY
})
}
document.addEventListener('click', mouseClickHandle)
// 在此處返回一個(gè)解綁函數(shù)即可
return ()=>{
console.log('點(diǎn)擊了d')
document.removeEventListener('click', mouseClickHandle)
}
})
console.log('點(diǎn)擊了a')
當(dāng)返回一個(gè)解綁函數(shù)后再次測(cè)試發(fā)現(xiàn)砌滞,在組件在執(zhí)行下一個(gè) effect 之前侮邀,上一個(gè) effect 就已被清除(d在b之前打印可以印證這點(diǎn))。
下面再來(lái)印證上述提到的第二個(gè)參數(shù)為空數(shù)組的情況:
useEffect(()=>{
console.log('點(diǎn)擊了b')
const mouseClickHandle = (e) =>{
console.log('點(diǎn)擊了c')
setPosition({
x: e.clientX,
y: e.clientY
})
}
document.addEventListener('click', mouseClickHandle)
return ()=>{
console.log('點(diǎn)擊了d')
document.removeEventListener('click', mouseClickHandle)
}
},[])
console.log('點(diǎn)擊了a')
可以看到贝润,當(dāng)?shù)诙€(gè)參數(shù)為空數(shù)組的時(shí)候绊茧,b和d都沒(méi)有打印,說(shuō)明此時(shí)useEffect并不被執(zhí)行打掘,執(zhí)行的只是初始進(jìn)入就綁定的事件华畏。