React?useEffect不支持async?function示例分析
引言
useEffect相比大家都耳熟能詳啦,如下這種寫(xiě)法,應(yīng)該是非常常見(jiàn)的需求。
useEffect(async () => { await getPoiInfo(); // 請(qǐng)求數(shù)據(jù) }, []);
但是 React 本身并不支持這么做,理由是 effect function 應(yīng)該返回一個(gè)銷(xiāo)毀函數(shù)(effect:是指return返回的cleanup函數(shù)),如果 useEffect 第一個(gè)參數(shù)傳入 async,返回值則變成了 Promise,會(huì)導(dǎo)致 react 在調(diào)用銷(xiāo)毀函數(shù)的時(shí)候報(bào)錯(cuò) :function.apply is undefined。
React為什么這么設(shè)計(jì)呢?
1、useEffect 的返回值是要在卸載組件時(shí)調(diào)用的,React 需要在 mount 的時(shí)候馬上拿到這個(gè)值,不然就亂套了
2、useEffect() 可能有個(gè)潛在邏輯:第二次觸發(fā) useEffect 里的回調(diào)前,前一次觸發(fā)的行為都執(zhí)行完成,返回的清理函數(shù)也執(zhí)行完成。這樣邏輯才清楚。而如果是異步的,情況會(huì)變得很復(fù)雜,可能會(huì)很容易寫(xiě)出有 bug 的代碼。
下面有兩種改進(jìn)的方法大家可以參考下:
簡(jiǎn)單改造
1、簡(jiǎn)單改造的寫(xiě)法(不推薦)
第一種 在內(nèi)部創(chuàng)建一個(gè)異步函數(shù)anyNameFunction,等待他的結(jié)果,然后調(diào)用setData
但是這種方式存在一個(gè)問(wèn)題,如果asyncFunction請(qǐng)求有依賴(lài)外部的參數(shù),如果不更新requestData 的 effect 的依賴(lài),effect 就不會(huì)同步 props 和 state 帶來(lái)的變更,也就不回重新請(qǐng)求數(shù)據(jù)
useEffect(() => { // Create an scoped async function in the hook // 注意如果函數(shù)沒(méi)有使用組件內(nèi)的任何值,可以把它提到組件外面去定義 // 下面代碼可以提到外面,可以自由地在 effect 中使用,下面就不改啦 async function asyncFunction() { await requestData(); setData(data) } // Execute the created function directly anyNameFunction(); }, []); // 這里設(shè)置成[]數(shù)組,因?yàn)槲覀冎幌朐趻燧d的時(shí)候運(yùn)行它一次
或者 useEffect中異步函數(shù)采用IIFE寫(xiě)法( Immediately Invoked Function Expression即立即調(diào)用的函數(shù)式表達(dá)式)
useEffect(() => { // Using an IIFE (async function anyNameFunction() { await requestData(); })(); }, []);
2、把異步提取成單獨(dú)函數(shù)或自定義hook(推薦)
第一種自定義 hook包裹,然后再effect中通過(guò)promise.then調(diào)用(github上大佬給的答案:github)
// 自定義hook function useAsyncEffect(effect: () => Promise<void | (() => void)>, dependencies?: any[]) { return useEffect(() => { const cleanupPromise = effect() return () => { cleanupPromise.then(cleanup => cleanup && cleanup()) } }, dependencies) } // 使用 useAsyncEffect(async () => { const count = await fetchData() setCount(count) }, [fetchData])
或者利用useCallback 包裝成hook
useCallback 本質(zhì)上是添加了一層依賴(lài)檢查,使用useCallback,函數(shù)完全可以參與到數(shù)據(jù)流中,可以說(shuō)如果一個(gè)函數(shù)的輸入改變了,這個(gè)函數(shù)就改變了,如果沒(méi)有,函數(shù)也不會(huì)改變。
下面的例子中會(huì)依賴(lài) type ,如果 type 保持不變,requestData 也會(huì)保持不變,effect 也不會(huì)重新運(yùn)行,但是如果 type 修改了,requestData 也會(huì)隨之改變,因此會(huì)重新請(qǐng)求數(shù)據(jù)。
// 封裝 const requestData = useCallback(async () => { changeLoading(true); changeError(false); changeList([]); requestAPI.getFeature({ type }).then((data) => { if (data) { changeList(data); } }).catch((e) => { changeError(true); }).finally(() => { changeLoading(false); }); }, [type]); // type改變會(huì)重新生成函數(shù) // 普通接口請(qǐng)求 useEffect(() => { requestData(); }, [requestData]); // 單獨(dú)處理外層刷新的接口請(qǐng)求 // refreshing是props傳遞的過(guò)來(lái)的,不應(yīng)該與state狀態(tài)改變混在一起,這也是hook的優(yōu)勢(shì),將不相關(guān)的狀態(tài)邏輯拆分成更細(xì)粒度 useEffect(() => { if (!refreshing) { return; } requestData().then(() => { getRefreshStatus(false); }); }, [refreshing]);
關(guān)于為什么不支持異步的原理可以看下這篇文章里通過(guò)源碼的分析:useEffect 中為啥不能使用 async
有任何疑問(wèn)歡迎評(píng)論溝通,我會(huì)繼續(xù)更新!
其他相關(guān)文檔:
https://heptaluan.github.io/2020/11/07/React/17/
https://www.robinwieruch.de/react-hooks-fetch-data/
以上就是React useEffect不支持async function示例分析的詳細(xì)內(nèi)容,更多關(guān)于useEffect不支持async function的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
reset.css瀏覽器默認(rèn)樣式表重置(user?agent?stylesheet)的示例代碼
這篇文章主要介紹了reset.css瀏覽器默認(rèn)樣式表重置(user?agent?stylesheet),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-12-12react實(shí)現(xiàn)動(dòng)態(tài)表單
這篇文章主要為大家詳細(xì)介紹了react實(shí)現(xiàn)動(dòng)態(tài)表單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08解決React報(bào)錯(cuò)Cannot assign to 'current'
這篇文章主要為大家介紹了React報(bào)錯(cuò)Cannot assign to 'current' because it is a read-only property的解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12原生+React實(shí)現(xiàn)懶加載(無(wú)限滾動(dòng))列表方式
這篇文章主要介紹了原生+React實(shí)現(xiàn)懶加載(無(wú)限滾動(dòng))列表方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03解析react?函數(shù)組件輸入卡頓問(wèn)題?usecallback?react.memo
useMemo是一個(gè)react hook,我們可以使用它在組件中包裝函數(shù)??梢允褂盟鼇?lái)確保該函數(shù)中的值僅在依賴(lài)項(xiàng)之一發(fā)生變化時(shí)才重新計(jì)算,這篇文章主要介紹了react?函數(shù)組件輸入卡頓問(wèn)題?usecallback?react.memo,需要的朋友可以參考下2022-07-07