React中的useEffect(副作用)介紹
useEffect(副作用)介紹
useEffect是用來(lái)使函數(shù)組件也可以進(jìn)行副作用操作的。
那么什么是副作用呢?
函數(shù)的副作用就是函數(shù)除了返回值外對(duì)外界環(huán)境造成的其它影響。
舉個(gè)例子,假如我們每次執(zhí)行一個(gè)函數(shù),該函數(shù)都會(huì)操作全局的一個(gè)變量,那么對(duì)全局變量的操作就是這個(gè)函數(shù)的副作用。而在React的世界里,我們的副作用大體可以分為兩類,一類是調(diào)用瀏覽器的API,例如使用addEventListener來(lái)添加事件監(jiān)聽(tīng)函數(shù)等,另外一類是發(fā)起獲取服務(wù)器數(shù)據(jù)的請(qǐng)求,例如當(dāng)用戶組件掛載的時(shí)候去異步獲取用戶的信息等。
react官方的原話:
如果你熟悉 React class 的生命周期函數(shù),你可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個(gè)函數(shù)的組合。
- componentDidMount 組件掛載
- componentDidUpdate 組件更新
- componentWillUnmount 組件將要摧毀
語(yǔ)法:
import {useEffect} from "react" useEffect(() => { /** 執(zhí)行邏輯 */ }, dependencies) //dependencies是一個(gè)數(shù)組,是可選的 //或者: useEffect(effect?=>clean?, dependencies?)
useEffect的第一個(gè)參數(shù) effect 是要執(zhí)行的副作用函數(shù),它可以是任意的用戶自定義函數(shù),用戶可以在這個(gè)函數(shù)里面操作一些瀏覽器的API或者和外部環(huán)境進(jìn)行交互,網(wǎng)絡(luò)請(qǐng)求等,這個(gè)函數(shù)會(huì)在每次組件渲染完成之后被調(diào)用。
useEffect可以有一個(gè)返回值,返回一個(gè)函數(shù),系統(tǒng)在組件重新渲染之前調(diào)用,用于清除副作用(比如說(shuō)副作用是定時(shí)器,return里面就可以寫(xiě)清除定時(shí)器的代碼)。它第二個(gè)參數(shù)dependencies(依賴項(xiàng))來(lái)限制該副作用的執(zhí)行條件
useEffect(副作用)各種寫(xiě)法的調(diào)用時(shí)刻
1.寫(xiě)法一:沒(méi)有依賴項(xiàng)時(shí)
useEffect所在組件每次渲染(包括首次)時(shí)都要調(diào)用:組件中任何變化都會(huì)執(zhí)行(eg:useState解構(gòu)出的state改了就會(huì)引發(fā)組件重新渲染,父組件給子組件傳遞屬性的值改變,子組件中的useEffect就會(huì)執(zhí)行)
//沒(méi)有依賴項(xiàng) useEffect(()=>{ console.log('組件每次渲染時(shí)都要調(diào)用(頁(yè)面每次刷新)'); })
組件生命周期里面有一種生命周期父組件給子組件傳新的屬性就會(huì)調(diào)用的生命周期函數(shù),useEffect寫(xiě)法一就可以替代。
組件自身狀態(tài)變化會(huì)調(diào)用beforeupdate和updated,useEffect寫(xiě)法一就可以替代。
父組件給子組件傳值:
2.寫(xiě)法二:依賴項(xiàng)中有監(jiān)聽(tīng)的值時(shí)
根據(jù)依賴項(xiàng)中監(jiān)聽(tīng)的變量是否變化決定是否執(zhí)行副作用,變了就執(zhí)行,不變就不執(zhí)行。
//依賴項(xiàng)中有值時(shí) //頁(yè)面首次渲染和父組件給子組件傳的屬性值和子組件自身的值改變(依賴項(xiàng)改變才會(huì)打印) useEffect(() => { console.log('頁(yè)面首次渲染和依賴項(xiàng)改變的時(shí)候才會(huì)打印'); },[num,props.title])
3.寫(xiě)法三:依賴項(xiàng)為空數(shù)組時(shí)
相當(dāng)于Vue生命周期函數(shù)mounted,也就是頁(yè)面首次渲染(掛載)后,后面不管組件中值咋改變都不會(huì)執(zhí)行了,除非該組件銷毀了再重新掛載時(shí)才會(huì)執(zhí)行。
useEffect(() => { console.log('頁(yè)面首次渲染'); },[])
4.寫(xiě)法四:清除副作用寫(xiě)法
(假如副作用是一個(gè)定時(shí)器,清除定時(shí)器,如果不清的話,會(huì)出現(xiàn)內(nèi)存泄漏)
useEffect(() => { let timer = setInterval(()=>{ console.log(66666); },1000) return ()=>{ //當(dāng)組件下一次渲染前,執(zhí)行這個(gè)函數(shù):清除副作用(計(jì)時(shí)器就是一種副作用) console.log('當(dāng)組件下一次渲染前,執(zhí)行這個(gè)函數(shù):清除副作用'); clearInterval(timer); } })//這里沒(méi)寫(xiě)依賴項(xiàng),所以頁(yè)面中的值改變就會(huì)刷新,比如useState解構(gòu)出的state改變
問(wèn)題:副作用函數(shù)不會(huì)有緩存,那為什么在副作用函數(shù)useEffect里面寫(xiě)了定時(shí)器,頁(yè)面(組件)刷新之后上一個(gè)定時(shí)器沒(méi)有清除?
就非要寫(xiě)return 返回一個(gè)函數(shù)去清除副作用(定時(shí)器)
5.寫(xiě)法五:依賴項(xiàng)是一個(gè)函數(shù)的時(shí)候
let fn = ()=>{ console.log(11111111); } useEffect(() => { console.log('此組件渲染時(shí),就會(huì)運(yùn)行(包括首次渲染)'); // 該組件渲染時(shí)(包括首次渲染),就會(huì)執(zhí)行副作用 let timer = setInterval(()=>{ console.log(66666); },1000) return ()=>{ //而當(dāng)該組件下一次運(yùn)行(渲染)時(shí),才會(huì)執(zhí)行清除副作用函數(shù)(第一次渲染不執(zhí)行(組件首次渲染時(shí)),下一次渲染才執(zhí)行) console.log('當(dāng)組件下一次渲染前,執(zhí)行這個(gè)函數(shù):清除副作用'); clearInterval(timer); } },[fn])
分析:當(dāng)依賴項(xiàng) fn 函數(shù)運(yùn)行的時(shí)候,副作用函數(shù)才會(huì)運(yùn)行(先執(zhí)行副作用函數(shù)的return返回的函數(shù),把上一次渲染生成的定時(shí)器清除,才會(huì)執(zhí)行副作用函數(shù),重新生成一個(gè)定時(shí)器),但是return返回的函數(shù)不一定運(yùn)行,因?yàn)閞eturn返回的函數(shù)必須要是在該組件下一次渲染時(shí),才會(huì)執(zhí)行。因?yàn)閒n函數(shù)雖然執(zhí)行,但是并沒(méi)有引起組件重新渲染,所以并不會(huì)執(zhí)行return返回的函數(shù)。
缺點(diǎn)是:函數(shù)組件刷新時(shí),函數(shù)fn又會(huì)重新生成一模一樣的,沒(méi)必要,會(huì)占用內(nèi)存。有沒(méi)有一種技術(shù),在組件刷新時(shí),這種像fn函數(shù)的,不重新生成,就用原來(lái)內(nèi)存中的fn,就不用去重新開(kāi)辟內(nèi)存空間去生成函數(shù)fn。所以就用到了useCallback
注意點(diǎn)
1.
//這種沒(méi)依賴項(xiàng) let [data,setData] = useState(''); useEffect(()=>{ //這里可以進(jìn)行請(qǐng)求后臺(tái)數(shù)據(jù),但是不能通過(guò)setData()將請(qǐng)求回來(lái)的數(shù)據(jù)把頁(yè)面刷新 //會(huì)陷入死循環(huán),頁(yè)面一刷新 useEffect就會(huì)執(zhí)行,就會(huì)請(qǐng)求后臺(tái)數(shù)據(jù),請(qǐng)求回來(lái)的數(shù)據(jù)又 //通過(guò)setData()導(dǎo)致頁(yè)面數(shù)據(jù)改變?nèi)缓笏⑿拢@樣就會(huì)陷入死循環(huán) setData(); }) //如果有依賴項(xiàng)的話,就不會(huì)陷入死循環(huán)
2.組件重新渲染時(shí),會(huì)將那些非hook相關(guān)的數(shù)據(jù)重新生成一份,比如說(shuō),
let [num,setNum] = useState(100); //hook相關(guān)的數(shù)據(jù) let m = 100; //普通的數(shù)據(jù) let arr = [100,200,900];//普通的引用數(shù)據(jù) let fm = ()=>{} //普通的引用數(shù)據(jù)
以u(píng)se開(kāi)頭的那些hook組件刷新時(shí)不會(huì)重新生成,那些普通的數(shù)據(jù)會(huì)重新生成。
如果依賴項(xiàng)是這種普通的arr,fm等引用數(shù)據(jù),組件刷新時(shí),就會(huì)重新生成,重新開(kāi)辟內(nèi)存空間生成,所以就會(huì)導(dǎo)致副作用函數(shù)執(zhí)行,所以一般副作用函數(shù)的依賴項(xiàng)都是父組件給子組件傳的屬性或者useState解構(gòu)出的state值這些。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- React Hook useState useEffect componentDidMount componentDidUpdate componentWillUnmount問(wèn)題
- React中useEffect原理的代碼簡(jiǎn)單實(shí)現(xiàn)詳解
- React之useEffect缺少依賴警告問(wèn)題及解決
- React Hooks: useEffect()調(diào)用了兩次問(wèn)題分析
- React中useEffect Hook常見(jiàn)問(wèn)題及解決
- useEffect如何通過(guò)form.getFieldValue(‘xxx‘)監(jiān)聽(tīng)Form表單變化
相關(guān)文章
ReactNative頁(yè)面跳轉(zhuǎn)實(shí)例代碼
這篇文章主要介紹了ReactNative頁(yè)面跳轉(zhuǎn)的代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09React Native 混合開(kāi)發(fā)多入口加載方式詳解
這篇文章主要介紹了React Native 混合開(kāi)發(fā)多入口加載方式詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09關(guān)于react ant 組件 Select下拉框 值回顯的問(wèn)題
這篇文章主要介紹了關(guān)于react ant 組件 Select下拉框 值回顯的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08React如何將組件渲染到指定DOM節(jié)點(diǎn)詳解
這篇文章主要給大家介紹了關(guān)于React如何將組件渲染到指定DOM節(jié)點(diǎn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)下吧。2017-09-09React項(xiàng)目中使用Redux的?react-redux
這篇文章主要介紹了React項(xiàng)目中使用Redux的?react-redux,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09React項(xiàng)目經(jīng)驗(yàn)總結(jié)及遇到的坑
這篇文章主要介紹了React項(xiàng)目經(jīng)驗(yàn)總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07reset.css瀏覽器默認(rèn)樣式表重置(user?agent?stylesheet)的示例代碼
這篇文章主要介紹了reset.css瀏覽器默認(rèn)樣式表重置(user?agent?stylesheet),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-12-12