自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從源碼理清 UseEffect 第二個參數(shù)是怎么處理的

開發(fā) 前端
useEffect 第二個參數(shù)傳入 undefined、[]、[a,b,c] 時執(zhí)行的效果不同, undefined 每次都會執(zhí)行,而依賴數(shù)組只有在依賴變了才會執(zhí)行,空數(shù)組只會執(zhí)行一次。

useEffect 是常用的 hook,它支持兩個參數(shù),第一個參數(shù)是回調(diào)函數(shù),第二個參數(shù)是依賴。

當?shù)诙€參數(shù)為 null 或 undefined 的時候,回調(diào)函數(shù)每次 render 都會執(zhí)行,而參數(shù)為數(shù)組的時候,只有依賴項變了才會執(zhí)行。

這些我們都很熟悉了,但它是怎么實現(xiàn)的呢?我們來從源碼來找下答案。

useEffect 的第二個參數(shù)

我們先來試一下第二個參數(shù)傳入 undefined、空數(shù)組、有依賴的數(shù)組時的效果。

準備這樣一段代碼:

import { useEffect, useRef, useState } from 'react';

function Dong() {
const ref = useRef(1);
const [,setState] = useState();
useEffect(() => {
console.log(111);
});
useEffect(() => {
console.log(222);
}, []);
useEffect(() => {
console.log(333);
}, [ref.current]);
useEffect(() => {
setInterval(() => {
setState([]);
}, 1000);
setTimeout(() => {
ref.current = 2;
}, 3000);
}, []);
return <div>dong</div>;
}

我們用寫了三個 useEffect,第二個參數(shù)分別為 undefined、[]、有一個依賴的數(shù)組,回調(diào)函數(shù)里分別打印 111、222、333。

然后 useState 聲明了一個 state,用 setInterval 定時修改,這樣能不斷觸發(fā) render。

又用 useRef 聲明了一個對象,它的特點是每次 render 都是返回的同一個對象,我們用 setTimeout 在 2s 后修改了它的值。

執(zhí)行的結(jié)果大家應(yīng)該很容易想到:

111 每次都會打印,因為第二個參數(shù)為 undefined。

222 只打印一次,因為第二個參數(shù)為 []。

333 打印兩次,因為第二個參數(shù)有一個依賴,這個依賴在 2s 的時候會變一次。

這些我們都很熟悉了,但是它為什么是這樣呢?

我們來看下源碼:

useEffect 相關(guān)源碼

react hooks 的原理前面一篇文章寫過,我們再過一遍:

jsx 編譯產(chǎn)生 render function,執(zhí)行返回 vdom,但是為了提高性能,React 16 引入 fiber 架構(gòu),會先把 vdom 轉(zhuǎn)成 fiber,然后再去更新到 dom。

vdom 轉(zhuǎn) fiber 的過程叫做 reconcile,更新到 dom 的過程叫做 commit。reconcile 的過程是可打斷的,需要 schedule。

hooks 也是基于 fiber 來實現(xiàn)的,它在 fiber 節(jié)點上維護了一個鏈表(memorizedState 屬性),用來保存數(shù)據(jù),每個 hook 都是從對應(yīng)的鏈表元素上存取各自的數(shù)據(jù)。

比如上面那個組件的 6 個 hook 就對應(yīng)著 fiber 節(jié)點上 memorizedState 鏈表的 6 個元素:

每個 hook 都是在對應(yīng)的鏈表元素上存取數(shù)據(jù)的。

這個鏈表有個建立的過程,叫做 mount,后面只需要 update,所以每個 hook 的實現(xiàn)都會分為 mount 和 update 兩個階段。

我們看下 useEffect 相關(guān)的源碼:

它也是分為了 mountEffect 和 updateEffect 兩個函數(shù),最終都是在 hook.memorizedState 存取元素的。這就是 hook 的通用原理。

第二個參數(shù)對應(yīng)的就是 deps,它是怎么判斷是否要更新的呢?

我們著重看下這段邏輯:

deps 是新傳入的參數(shù),如果是 undefined 會作為 null。

hook.memorizedState.deps 取到的是之前的 deps。

然后新舊 deps 會做下對比,如果返回 true 才會執(zhí)行 effect。

對比的邏輯在 areHookInputsEqual 這個函數(shù)里:

如果 prevDeps 是 null,那就直接返回 false,這就是 useEffect 第二個參數(shù)傳 undefined 或者 null 的話 effect 函數(shù)都會執(zhí)行的原因。

否則,才會新舊的 deps 數(shù)組中每個元素做對比,有一個不一樣就返回 false。

這已經(jīng)解釋了上面那個案例,deps 數(shù)組傳 undefined、[]、[dep] 時 effect 執(zhí)行的不同情況。

其實還有一種情況也會導致 effect 執(zhí)行,就是上面這段邏輯:

當熱更新的時候,就算依賴沒有變,也需要重新執(zhí)行 effect,這個是通過 ignorePreviousDependencies 變量來控制的。

這個估計很多人都不知道,因為熱更新是工具實現(xiàn)的。

我們從源碼層面解釋清楚了 useEffect 第二個參數(shù)的處理機制。

其實 useCallback、useMemo 的 deps 參數(shù)處理邏輯也是一樣的,源碼都差不多:

總結(jié)

useEffect 第二個參數(shù)傳入 undefined、[]、[a,b,c] 時執(zhí)行的效果不同, undefined 每次都會執(zhí)行,而依賴數(shù)組只有在依賴變了才會執(zhí)行,空數(shù)組只會執(zhí)行一次。

我們從源碼層面解釋了原因:

hooks 是在 fiber 節(jié)點的 memorizedState 屬性上存取數(shù)據(jù)的,會組織一個和 hook 一一對應(yīng)的鏈表。

構(gòu)建這個鏈表的階段叫 mount,后面只需要 update,所以所有的 hook 的實現(xiàn)都分為了 mountXxx 和 updateXxx 兩部分。

useEffect 在 update 時會對比新傳入的 deps 和之前存在 memorizedState 上的 deps 來確定是否執(zhí)行 effect 回調(diào),它做了這樣的處理:

當 dep 是 null(undefined 也會處理成 null)時,判定為不相等。如果是熱更新的時候,判定為不相等。否則會對比數(shù)組的每個依賴項來判斷是否相等。只要新舊 deps 不相等就執(zhí)行 effect。

useCallback、useMemo 的 deps 處理也是一樣的,我們從源碼層面理清楚了 deps 參數(shù)的處理機制。

責任編輯:姜華 來源: 神光的編程秘籍
相關(guān)推薦

2023-11-26 17:59:00

React組件參數(shù)

2009-11-05 09:54:03

盜版黨歐洲議會

2020-09-11 10:27:07

鴻蒙安卓操作系統(tǒng)

2011-05-23 10:16:25

VMware微軟

2016-07-07 13:20:43

阿里云計算yunos

2011-09-21 13:09:33

HTML 5

2022-05-18 10:26:21

微軟Linux穩(wěn)定版

2011-11-01 10:21:16

UbuntuAndroid

2011-02-18 14:04:27

Ubuntu 10.0

2015-08-12 11:35:32

Windows 10Windows 8

2010-10-08 11:29:45

AndroidiPhone

2021-05-17 18:56:20

甲骨文云區(qū)域

2012-05-07 23:41:43

JavaJVMCeylon

2010-10-25 06:33:43

戴爾dell虛擬化

2009-02-09 09:13:13

Windows 7BetaUAC

2022-03-26 09:39:53

SOC運營數(shù)據(jù)

2017-05-17 06:34:18

Android谷歌

2010-10-14 13:54:07

AT&T

2019-06-19 09:00:33

驅(qū)動器安裝Windows 10
點贊
收藏

51CTO技術(shù)棧公眾號