您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“ahooks控制時(shí)機(jī)的hook如何實(shí)現(xiàn)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“ahooks控制時(shí)機(jī)的hook如何實(shí)現(xiàn)”吧!
學(xué)習(xí)類似 React 和 Vue 這種框架,對(duì)它們生命周期的掌握都是必須的,我們需要清楚的知道我們代碼的執(zhí)行順序,并且在不同的階段執(zhí)行不同操作的代碼,比如需要掛載完成之后才去獲取 dom 的值,否則可能會(huì)獲取不到相應(yīng)的值。
使用過(guò) React 的 Class Component 的同學(xué),就會(huì)知道其組件生命周期會(huì)分成三個(gè)狀態(tài):
Mounting(掛載):已插入真實(shí) DOM
Updating(更新):正在被重新渲染
Unmounting(卸載):已移出真實(shí) DOM
簡(jiǎn)單版如下所示:
其中每個(gè)狀態(tài)中還會(huì)按順序調(diào)用不同的方法,對(duì)應(yīng)的詳細(xì)如下(這里不展開(kāi)說(shuō)):
可以通過(guò)官方提供這個(gè)網(wǎng)站查看詳情
可以看到,會(huì)有非常多的生命周期方法,而且在不同的版本,生命周期方法還不同。
到了 Function Component ,會(huì)發(fā)現(xiàn)沒(méi)有直接提及生命周期的概念,它是更徹底的狀態(tài)驅(qū)動(dòng),它只有一個(gè)狀態(tài),React 負(fù)責(zé)將狀態(tài)渲染到視圖中。
對(duì)于 Function Component 來(lái)說(shuō)由狀態(tài)到頁(yè)面渲染只有三步:
輸入狀態(tài)(prop、state)
執(zhí)行組件的邏輯,并在 useEffect/useLayoutEffect
中訂閱副作用
輸出UI(Dom節(jié)點(diǎn))
重點(diǎn)是第二步,React 通過(guò) useEffect/useLayoutEffect 訂閱副作用。Class Component 中的生命周期都可以通過(guò) useEffect/useLayoutEffect 來(lái)實(shí)現(xiàn)。它們兩個(gè)的功能非常相似,我們這里看下 useEffect。
使用 useEffect 相當(dāng)于告訴 React 組件需要在渲染后執(zhí)行某些操作,React 將在執(zhí)行 DOM 更新之后調(diào)用它。React 保證了每次運(yùn)行 useEffect 的時(shí)候,DOM 已經(jīng)更新完畢。這就實(shí)現(xiàn)了 Class Component 中的 Mounting(掛載階段)。
當(dāng)狀態(tài)發(fā)生變化的時(shí)候,它能夠執(zhí)行對(duì)應(yīng)的邏輯、更行狀態(tài)并將結(jié)果渲染到視圖中,這就完成了 Class Component 中的 Updating(更新階段)。
最后通過(guò)在 useEffect 中返回一個(gè)函數(shù),它便可以清理副作用。它的規(guī)則是:
首次渲染不會(huì)進(jìn)行清理,會(huì)在下一次渲染,清除上一次的副作用。
卸載階段也會(huì)執(zhí)行清除操作。
通過(guò)返回一個(gè)函數(shù),我們就能實(shí)現(xiàn) Class Component 中的 Unmounting(卸載階段)。
基于 useEffect/useLayoutEffect,ahooks 做了一些封裝,能夠讓你更加清晰的知道你的代碼執(zhí)行時(shí)機(jī)。
只在組件初始化時(shí)執(zhí)行的 Hook。 useEffect 依賴假如為空,只會(huì)在組件初始化的時(shí)候執(zhí)行。
// 省略部分代碼 const useMount = (fn: () => void) => { // 省略部分代碼 // 單純就在 useEffect 基礎(chǔ)上封裝了一層 useEffect(() => { fn?.(); }, []); }; export default useMount;
useUnmount,組件卸載(unmount)時(shí)執(zhí)行的 Hook。
useEffect 可以在組件渲染后實(shí)現(xiàn)各種不同的副作用。有些副作用可能需要清除,所以需要返回一個(gè)函數(shù),這個(gè)函數(shù)會(huì)在組件卸載的時(shí)候執(zhí)行。
const useUnmount = (fn: () => void) => { const fnRef = useLatest(fn); useEffect( // 在組件卸載(unmount)時(shí)執(zhí)行的 Hook。 // useEffect 的返回值中執(zhí)行函數(shù) () => () => { fnRef.current(); }, [], ); }; export default useUnmount;
獲取當(dāng)前組件是否已經(jīng)卸載的 Hook。
通過(guò)判斷有沒(méi)有執(zhí)行 useEffect 中的返回值判斷當(dāng)前組件是否已經(jīng)卸載。
// 獲取當(dāng)前組件是否已經(jīng)卸載的 Hook。 const useUnmountedRef = () => { const unmountedRef = useRef(false); useEffect(() => { unmountedRef.current = false; // 如果已經(jīng)卸載,則會(huì)執(zhí)行 return 中的邏輯 return () => { unmountedRef.current = true; }; }, []); return unmountedRef; }; export default useUnmountedRef;
這里只會(huì)講官方文檔 Effect
下面的幾個(gè),有部分是定時(shí)器、防抖節(jié)流等,咱們后面的系列具體分析。
useUpdateEffect 和 useUpdateLayoutEffect 的用法跟 useEffect 和 useLayoutEffect 一樣,只是會(huì)忽略首次執(zhí)行,只在依賴更新時(shí)執(zhí)行。
實(shí)現(xiàn)思路:初始化一個(gè)標(biāo)識(shí)符,剛開(kāi)始為 false。當(dāng)首次執(zhí)行完的時(shí)候,置為 true。只有標(biāo)識(shí)符為 true 的時(shí)候,才執(zhí)行回調(diào)函數(shù)。
// 忽略首次執(zhí)行 export const createUpdateEffect: (hook: effectHookType) => effectHookType = (hook) => (effect, deps) => { const isMounted = useRef(false); // for react-refresh hook(() => { return () => { isMounted.current = false; }; }, []); hook(() => { // 首次執(zhí)行完時(shí)候,設(shè)置為 true,從而下次依賴更新的時(shí)候可以執(zhí)行邏輯 if (!isMounted.current) { isMounted.current = true; } else { return effect(); } }, deps); };
用法與 useEffect 一致,但 deps 通過(guò) lodash isEqual 進(jìn)行深比較。
通過(guò) useRef 保存上一次的依賴的值,跟當(dāng)前的依賴對(duì)比(使用 lodash 的 isEqual),并將對(duì)比結(jié)果作為 useEffect 的依賴項(xiàng),從而決定回調(diào)函數(shù)是否執(zhí)行。
const depsEqual = (aDeps: DependencyList, bDeps: DependencyList = []) => { return isEqual(aDeps, bDeps); }; const useDeepCompareEffect = (effect: EffectCallback, deps: DependencyList) => { // 通過(guò) useRef 保存上一次的依賴的值 const ref = useRef<DependencyList>(); const signalRef = useRef<number>(0); // 判斷最新的依賴和舊的區(qū)別 // 如果相等,則變更 signalRef.current,從而觸發(fā) useEffect 中的回調(diào) if (!depsEqual(deps, ref.current)) { ref.current = deps; signalRef.current += 1; } useEffect(effect, [signalRef.current]); };
useUpdate 會(huì)返回一個(gè)函數(shù),調(diào)用該函數(shù)會(huì)強(qiáng)制組件重新渲染。
返回的函數(shù)通過(guò)變更 useState 返回的 state,從而促使組件進(jìn)行更新。
import { useCallback, useState } from 'react'; const useUpdate = () => { const [, setState] = useState({}); // 通過(guò)設(shè)置一個(gè)全新的狀態(tài),促使 function 組件更新 return useCallback(() => setState({}), []); }; export default useUpdate;
到此,相信大家對(duì)“ahooks控制時(shí)機(jī)的hook如何實(shí)現(xiàn)”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。