<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文是深入淺出 ahooks 原始碼系列文章的第五篇,這個系列的目標主要有以下幾點:
注:本系列對 ahooks 的原始碼解析是基於 v3.3.13
。自己 folk 了一份原始碼,主要是對原始碼做了一些解讀,可見 詳情。
本文來探索一下 ahooks 是怎麼封裝 React 的一些執行“時機”的?
學習類似 React 和 Vue 這種框架,對它們生命週期的掌握都是必須的,我們需要清楚的知道我們程式碼的執行順序,並且在不同的階段執行不同操作的程式碼,比如需要掛載完成之後才去獲取 dom 的值,否則可能會獲取不到相應的值。
使用過 React 的 Class Component 的同學,就會知道其元件生命週期會分成三個狀態:
簡單版如下所示:
其中每個狀態中還會按順序呼叫不同的方法,對應的詳細如下(這裡不展開說):
可以通過官方提供這個網站檢視詳情
可以看到,會有非常多的生命週期方法,而且在不同的版本,生命週期方法還不同。
到了 Function Component ,會發現沒有直接提及生命週期的概念,它是更徹底的狀態驅動,它只有一個狀態,React 負責將狀態渲染到檢視中。
對於 Function Component 來說由狀態到頁面渲染只有三步:
useEffect/useLayoutEffect
中訂閱副作用重點是第二步,React 通過 useEffect/useLayoutEffect 訂閱副作用。Class Component 中的生命週期都可以通過 useEffect/useLayoutEffect 來實現。它們兩個的功能非常相似,我們這裡看下 useEffect。
使用 useEffect 相當於告訴 React 元件需要在渲染後執行某些操作,React 將在執行 DOM 更新之後呼叫它。React 保證了每次執行 useEffect 的時候,DOM 已經更新完畢。這就實現了 Class Component 中的 Mounting(掛載階段)。
當狀態發生變化的時候,它能夠執行對應的邏輯、更行狀態並將結果渲染到檢視中,這就完成了 Class Component 中的 Updating(更新階段)。
最後通過在 useEffect 中返回一個函數,它便可以清理副作用。它的規則是:
通過返回一個函數,我們就能實現 Class Component 中的 Unmounting(解除安裝階段)。
基於 useEffect/useLayoutEffect,ahooks 做了一些封裝,能夠讓你更加清晰的知道你的程式碼執行時機。
只在元件初始化時執行的 Hook。 useEffect 依賴假如為空,只會在元件初始化的時候執行。
// 省略部分程式碼 const useMount = (fn: () => void) => { // 省略部分程式碼 // 單純就在 useEffect 基礎上封裝了一層 useEffect(() => { fn?.(); }, []); }; export default useMount;
useUnmount,元件解除安裝(unmount)時執行的 Hook。
useEffect 可以在元件渲染後實現各種不同的副作用。有些副作用可能需要清除,所以需要返回一個函數,這個函數會在元件解除安裝的時候執行。
const useUnmount = (fn: () => void) => { const fnRef = useLatest(fn); useEffect( // 在元件解除安裝(unmount)時執行的 Hook。 // useEffect 的返回值中執行函數 () => () => { fnRef.current(); }, [], ); }; export default useUnmount;
獲取當前元件是否已經解除安裝的 Hook。
通過判斷有沒有執行 useEffect 中的返回值判斷當前元件是否已經解除安裝。
// 獲取當前元件是否已經解除安裝的 Hook。 const useUnmountedRef = () => { const unmountedRef = useRef(false); useEffect(() => { unmountedRef.current = false; // 如果已經解除安裝,則會執行 return 中的邏輯 return () => { unmountedRef.current = true; }; }, []); return unmountedRef; }; export default useUnmountedRef;
這裡只會講官方檔案 Effect
下面的幾個,有部分是定時器、防抖節流等,咱們後面的系列具體分析。
useUpdateEffect 和 useUpdateLayoutEffect 的用法跟 useEffect 和 useLayoutEffect 一樣,只是會忽略首次執行,只在依賴更新時執行。
實現思路:初始化一個識別符號,剛開始為 false。當首次執行完的時候,置為 true。只有識別符號為 true 的時候,才執行回撥函數。
// 忽略首次執行 export const createUpdateEffect: (hook: effectHookType) => effectHookType = (hook) => (effect, deps) => { const isMounted = useRef(false); // for react-refresh hook(() => { return () => { isMounted.current = false; }; }, []); hook(() => { // 首次執行完時候,設定為 true,從而下次依賴更新的時候可以執行邏輯 if (!isMounted.current) { isMounted.current = true; } else { return effect(); } }, deps); };
用法與 useEffect 一致,但 deps 通過 lodash isEqual 進行深比較。
通過 useRef 儲存上一次的依賴的值,跟當前的依賴對比(使用 lodash 的 isEqual),並將對比結果作為 useEffect 的依賴項,從而決定回撥函數是否執行。
const depsEqual = (aDeps: DependencyList, bDeps: DependencyList = []) => { return isEqual(aDeps, bDeps); }; const useDeepCompareEffect = (effect: EffectCallback, deps: DependencyList) => { // 通過 useRef 儲存上一次的依賴的值 const ref = useRef<DependencyList>(); const signalRef = useRef<number>(0); // 判斷最新的依賴和舊的區別 // 如果相等,則變更 signalRef.current,從而觸發 useEffect 中的回撥 if (!depsEqual(deps, ref.current)) { ref.current = deps; signalRef.current += 1; } useEffect(effect, [signalRef.current]); };
useUpdate 會返回一個函數,呼叫該函數會強制元件重新渲染。
返回的函數通過變更 useState 返回的 state,從而促使元件進行更新。
import { useCallback, useState } from 'react'; const useUpdate = () => { const [, setState] = useState({}); // 通過設定一個全新的狀態,促使 function 元件更新 return useCallback(() => setState({}), []); }; export default useUpdate;
在我們寫程式碼的時候需要清晰的知道,元件的生命週期是怎樣的,我們程式碼的執行順序、執行的時機是怎樣的。
在 Function Component 中,使用 useEffect/useLayoutEffect 完成了 Class Components 生命週期的職責。ahooks 也是基於這兩個封裝了常見的程式碼執行時機,使用這些 hook,可以讓我們的程式碼更加具有可讀性以及邏輯更加清晰。
以上就是ahooks控制時機的hook實現方法的詳細內容,更多關於ahooks控制時機hook的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45