成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

React Hooks 的原理,有的簡單有的不簡單

開發 前端
React 支持 class 和 function 兩種形式的組件,class 支持 state 屬性和生命周期方法,而 function 組件也通過 hooks api 實現了類似的功能。

本文轉載自微信公眾號「神光的編程秘籍」,作者神說要有光。轉載本文請聯系神光的編程秘籍公眾號。

React 是實現了組件的前端框架,它支持 class 和 function 兩種形式的組件。

class 組件是通過繼承模版類(Component、PureComponent)的方式開發新組件的,這是 class 本身的特性,它支持設置 state,會在 state 改變后重新渲染,可以重寫一些父類的方法,這些方法會在 React 組件渲染的不同階段調用,叫做生命周期函數。

function 組件不能做繼承,因為 function 本來就沒這個特性,所以是提供了一些 api 供函數使用,這些 api 會在內部的一個數據結構上掛載一些函數和值,并執行相應的邏輯,通過這種方式實現了 state 和類似 class 組件的生命周期函數的功能,這種 api 就叫做 hooks。

hooks 掛載數據的數據結構叫做 fiber。

那什么是 fiber 呢?

我們知道,React 是通過 jsx 來描述界面結構的,會把 jsx 編譯成 render function,然后執行 render function 產生 vdom:

在 v16 之前的 React 里,是直接遞歸遍歷 vdom,通過 dom api 增刪改 dom 的方式來渲染的。但當 vdom 過大,頻繁調用 dom api 會比較耗時,而且遞歸又不能打斷,所以有性能問題。

后來就引入了 fiber 架構,先把 vdom 樹轉成 fiber 鏈表,然后再渲染 fiber。

vdom 轉 fiber 的過程叫做 reconcile,是可打斷的,React 加入了 schedule 的機制在空閑時調度 reconcile,reconcile 的過程中會做 diff,打上增刪改的標記(effectTag),并把對應的 dom 創建好。然后就可以一次性把 fiber 渲染到 dom,也就是 commit。

這個 schdule、reconcile、commit 的流程就是 fiber 架構。當然,對應的這個數據結構也叫 fiber。

hooks 就是通過把數據掛載到組件對應的 fiber 節點上來實現的。

fiber 節點是一個對象,hooks 把數據掛載在哪個屬性呢?

我們可以 debugger 看下。

準備這樣一個函數組件(代碼沒啥具體含義,就是為了調試 hooks):

function App() {
const [name, setName] = useState("guang");
useState('dong');

const handler = useCallback((evt) => {
setName('dong');
},[1]);

useEffect(() => {
console.log(1);
});

useRef(1);

useMemo(() => {
return 'guang and dong';
})

return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={handler}>
{name}
</p>
</header>
</div>
);
}

在函數打個斷點,運行到這個組件就會斷住。

我們看下調用棧:

上一個函數是 renderWithHooks,里面有個 workingInProgress 的對象就是當前的 fiber 節點:

fiber 節點的 memorizedState 就是保存 hooks 數據的地方。

它是一個通過 next 串聯的鏈表,展開看一下:

鏈表一共六個元素,這和我們在 function 組件寫的 hooks 不就對上了么:

這就是 hooks 存取數據的地方,執行的時候各自在自己的那個 memorizedState 上存取數據,完成各種邏輯,這就是 hooks 的原理。

這個 memorizedState 鏈表是什么時候創建的呢?

好問題,確實有個鏈表創建的過程,也就是 mountXxx。鏈表只需要創建一次,后面只需要 update。

所以第一次調用 useState 會執行 mountState,后面再調用 useState 會執行 updateState。

我們先集中精力把 mount 搞明白。

mountXxx 是創建 memorizedState 鏈表的過程,每個 hooks api 都是這樣的:

它的實現也很容易想到,就是創建對應的 memorizedState 對象,然后用 next 串聯起來,也就是這段代碼:

當然,創建這樣的數據結構還是為了使用的,每種 hooks api 都有不同的使用這些 memorizedState 數據的邏輯,有的比較簡單,比如 useRef、useCallback、useMemo,有的沒那么簡單,比如 useState、useEffect。

為什么這么說呢?我們看下它們的實現再說吧。

先看這幾個簡單的:

useRef

每個 useXxx 的 hooks 都有 mountXxx 和 updateXxx 兩個階段,比如 ref 就是 mountRef 和 updateRef。

它的代碼是最簡單的,只有這么幾行:

mountWorkInProgressHook 剛才我們看過,就是創建并返回 memorizedState 鏈表的,同理,下面那個 updateWorkInProgressHook 是更新的。

這些不用管,只要知道修改的是對應的 memorizedState 鏈表中的元素就行了。

那 ref 在 memorizedState 上掛了什么呢?

可以看到是把傳進來的 value 包裝了一個有 current 屬性的對象,凍結了一下,然后放在 memorizedState 屬性上。

后面 update 的時候,沒有做任何處理,直接返回這個對象。

所以,useRef 的功能就很容易猜到了:useRef 可以保存一個數據的引用,這個引用不可變。

這個 hooks 是最簡單的 hooks 了,給我們一個地方存數據,我們也能輕易的實現 useRef 這個 hooks。

再來看個稍難點的:

useCallback

useCallback 在 memorizedState 上放了一個數組,第一個元素是傳入的回調函數,第二個是傳入的 deps(對 deps 做了下 undefined 的處理)。

更新的時候把之前的那個 memorizedState 取出來,和新傳入的 deps 做下對比,如果沒變,那就返回之前的回調函數,也就是 prevState[0]。

如果變了,那就創建一個新的數組,第一個元素是傳入的回調函數,第二個是傳入的 deps。

所以,useCallback 的功能也就呼之欲出了:useCallback 可以實現函數的緩存,如果 deps 沒變就不會創建新的,否則才會返回新傳入的函數。

這段邏輯其實也不難,就是多了個判斷邏輯。

再來看個和它差不多的:

useMemo

useMemo 也在 memorizedState 上放了個數組,第一個元素是傳入函數的執行結果,第二個元素是 deps(對 deps 為 undefined 的情況做了下處理)。

更新的時候也是取出之前的 memorizedState,和新傳入的 deps 做下對比,如果沒變,就返回之前的值,也就是 prevState[0]。

如果變了,創建一個新的數組放在 memorizedState,第一個元素是新傳入函數的執行結果,第二個元素是 deps。

所以,useMemo 的功能大家也能猜出來:useMemo 可以實現函數執行結果的緩存,如果 deps 沒變,就直接拿之前的,否則才會執行函數拿到最新結果返回。

實現邏輯和 useCallback 大同小異。

這三個 hooks 難么?給大家一個對象來存儲數據,大家都能寫出來,并不難。

因為它們是沒有別的依賴的,只是單純的緩存了下值而已。而像 useState、useEffect 這些就復雜一些了,主要是因為需要調度。

useState

state 改了之后是要觸發更新的調度的,React 有自己的調度邏輯,就是我們前面提到的 fiber 的 schedule,所以需要 dispatch 一個 action。

(不展開講,簡單看一下)

這里詳細講要涉及到調度,就先不展開了。

useEffect

同樣的,effect 傳入的函數也是被 React 所調度的,當然,這里的調度不是 fiber 那個調度,而是單獨的 effect 調度:

(不展開講,簡單看一下)

hooks 負責把這些 effect 串聯成一個 updateQueue 的鏈表,然后讓 React 去調度執行。

所以說,useState、useEffect 這種 hooks 的實現是和 fiber 的空閑調度,effect 的調度結合比較緊密的,實現上更復雜了一些。

這里沒有展開講,因為這篇文章的目的是把 hooks 的主要原理理清楚,不會太深入細節。

大家可能還聽過自定義 hooks 的概念,那個是啥呢?

其實就是個函數調用,沒啥神奇的,我們可以把上面的 hooks 放到 xxx 函數里,然后在 function 組件里調用,對應的 hook 鏈表是一樣的。

只不過一般我們會使用 React 提供的 eslint 插件,lint 了這些函數必須以 use 開頭,但其實不用也沒事,它們和普通的函數封裝沒有任何區別。

總結

React 支持 class 和 function 兩種形式的組件,class 支持 state 屬性和生命周期方法,而 function 組件也通過 hooks api 實現了類似的功能。

fiber 架構是 React 在 16 以后引入的,之前是 jsx -> render function -> vdom 然后直接遞歸渲染 vdom,現在則是多了一步 vdom 轉 fiber 的 reconcile,在 reconcile 的過程中創建 dom 和做 diff 并打上增刪改的 effectTag,然后一次性 commit。這個 reconcile 是可被打斷的,可以調度,也就是 fiber 的 schedule。

hooks 的實現就是基于 fiber 的,會在 fiber 節點上放一個鏈表,每個節點的 memorizedState 屬性上存放了對應的數據,然后不同的 hooks api 使用對應的數據來完成不同的功能。

鏈表自然有個創建階段,也就是 mountXxx,之后就不需要再 mount 了,只需要 update。所以每個 useXx 的實現其實都是分為了 mountXxx 和 updateXxx 兩部分的。

我們看了幾個簡單的 hooks:useRef、useCallback、useMemo,它們只是對值做了緩存,邏輯比較純粹,沒有依賴 React 的調度。而 useState 會觸發 fiber 的 schedule,useEffect 也有自己的調度邏輯。實現上相對復雜一些,我們沒有繼續深入。

其實給我們一個對象來存取數據,實現 useRef、useCallback、useMemo 等 hooks 還是很簡單的。對于需要調度的,則復雜一些。

對于自定義的 hooks,那個就是個函數調用,沒有任何區別。(lint 的規則不想遵守可以忽略)

所有 hooks api 都是基于 fiber 節點上的 memorizedState 鏈表來存取數據并完成各自的邏輯的。

所以,hooks 的原理簡單么?只能說有的簡單,有的不簡單。

責任編輯:武曉燕 來源: 神光的編程秘籍
相關推薦

2014-12-19 10:07:10

C

2012-06-26 09:40:14

部署開發管理

2020-12-16 07:36:46

Redis字符串數據

2009-07-20 10:06:47

虛擬化思杰操作系統

2010-01-19 10:10:28

2010-12-06 09:45:27

TechEd 2010

2011-10-26 11:06:01

IBM朱近之華為

2020-11-11 15:36:51

服務器

2010-03-30 14:06:35

2013-06-04 17:10:00

Linux命令

2011-12-28 15:11:09

iOS推薦

2023-10-30 10:11:09

2014-02-24 14:45:23

XPath開發工具

2014-08-21 10:14:09

APP界面設計移動客戶端

2023-05-17 07:36:00

淺拷貝深拷貝對象

2012-10-18 13:26:03

多米音樂華為

2015-01-12 10:28:58

移動開發框架LettuceMobile Fram

2015-01-12 12:10:11

移動開發框架LettuceMobile Fram

2011-09-30 14:08:41

WiNetH3C

2020-12-21 10:55:41

Linux系統ls命令
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲男人天堂 | 一级免费毛片 | 毛片在线免费播放 | 一区二区三区四区电影视频在线观看 | 久久国产激情视频 | 一区二区三区国产精品 | 国产精品视频一区二区三区 | 欧美在线观看一区 | 欧美日韩成人在线观看 | 欧美日韩一区精品 | 国产一区二区三区欧美 | 一级特黄a大片 | 欧美国产一区二区 | 96国产精品久久久久aⅴ四区 | 少妇诱惑av | 国产一区 | 久久久www成人免费精品 | 国产欧美精品一区二区三区 | 国产情侣啪啪 | 日韩在线视频观看 | 久草新在线 | 日韩 欧美 综合 | 精品欧美一区二区在线观看 | 亚洲欧美在线一区 | 国产日产欧产精品精品推荐蛮挑 | 欧美日韩美女 | 激情亚洲 | 99只有精品 | eeuss国产一区二区三区四区 | 亚洲日本欧美日韩高观看 | 偷拍自拍在线观看 | 国产精品不卡一区二区三区 | 久久精品国产一区 | 久久国产精品一区二区三区 | 国产一区二区在线免费观看 | 亚洲综合视频 | 亚洲欧美综合精品久久成人 | 特黄色一级毛片 | 99小视频 | 在线免费国产视频 | 亚洲a一区 |