你真的理解 React Hooks 嗎

2022-08-30 06:30:17 字數 3274 閱讀 6211

react hooks 是在 react 16.8 版本新增的特性,在我看了 react 官網 和一些部落格對 react hook 的講解後還是覺得沒有 get 到本質。大部分的 react hook 的講解都是針對於 react hook 的作用、使用規則、定義規則等。對於新手來說還是覺得會使用但還是沒有入門。本篇部落格通過手動實現usestate()來了解 hook 的原理和本質。但是閱讀此篇部落格的前提是你要知道一些 react hooks 的基本用法和使用規則,要不然會看得雲裡霧裡。

react hook 說白了就是 react v18.6 新增的一些 api,api的本質就是提供某種功能的函式介面。因此,react hooks 就是一些函式,但是 react hooks 不是純函式。

什麼是純函式呢?就是此函式在相同的輸入值時,需產生相同的輸出,並且此函式不能影響到外面的資料。

簡單理解就是函式裡面不能用到在外面定義的變數,因為如果用到了外面定義的變數,當外面的變數改變時會影響函式內部的計算,函式也會影響到外面的變數。

對於 react hooks 提供的函式 api,恰恰就不是純函式。

來看乙個 usestate 的使用語句const [count, setcount] = usestate(0),使用 usestate 函式得到的結果並不是全都一樣的,因為如果usestate(0)每次得到的結果都是一樣的,那 count 值就永遠不會改變了,那 count 所在的頁面就永遠不會改變,和我們看到的結果就不一樣了。由此可知,react hooks 都不是純函式,也就是說 hooks 用到了函式外的變數。

那麼是什麼特性讓 react hooks 一定不能是純函式呢?實際上是 react 框架和函式元件本身決定的。我們知道,react 頁面渲染的原理就是通過每次 render 得到新的虛擬 dom ,然後進行 dom diff 來渲染頁面。而 react 的函式元件是通過執行整個函式得到乙個虛擬 dom。因此在每次頁面渲染 render 時,在函式元件內部的所有語句都會重新執行一次。如果在函式元件內部使用的 react hooks 是純函式的話,就不會在每次渲染後得到不同的虛擬 dom 了。

react 規定:所有 react 元件都必須是純函式,並禁止修改其自身 props 。

因此在 react v16.8 之前 react hooks 還沒出來的時候,函式元件因為是純函式,只能返回乙個固定的虛擬 dom,不能包含狀態,也不支援生命週期方法。因此,當時僅僅是支援函式元件,但函式元件相比於類元件限制太多,函式元件無法取代類元件,也沒類元件好用。

react 希望元件是簡單的而不是複雜的,react 認為元件的最佳寫法應該是函式,而不是類。因此 react 就新增了 react hooks,hook 就是鉤子的意思,是 react 提供給函式元件在需要外部功能和資料狀態時將其 「鉤」 進去,從而完善函式元件,使其能完全代替類元件。

react 的函式元件只能是純函式,那麼每次事件發生時重新 render 函式元件時得到不同的虛擬 dom 的事就完全交給了 react hooks,那麼 react hooks 是如何做到的呢?下面就手動實現乙個 usestate,usestate 的具體細節肯定不是這樣的,但原理和思路是一樣的。

react.usestate 的第一次執行是將初始值賦予給乙個 _state,之後的每次重新 render 時就是讀取 _state 的值。[state, setstate] 中的 setstate 做的事就是改變 _state 的值,然後重新渲染頁面。

根據這個原理實現 myusestate 函式如下:

import react from 'react';

import reactdom from 'react-dom';

let _state

function myusestate(initialvalue)

const setstate = (newvalue)=>

return [_state, setstate]

}function render()

const [n, setn] = myusestate(0)

return (

n: setn(n+1)}>+1

)}

上述實現的 myusestate 存在 bug,當在函式元件內用到兩次 myusestate 時就會出現問題了,二者共用乙個 _state 會出現混亂。

因此需要將上述實現進行改進,改進的思路就是將 _state 定義為乙個資料或者是物件,由於我們在函式使用時只傳了乙個數值,無法確定鍵值,因此只能使用資料。改進如下:

import react from 'react';

import reactdom from 'react-dom';

let _state =

let index = 0

function myusestate(initialvalue)

const setstate = (newvalue)=>

index++

return [_state[currentindex], setstate]

}function render()

const [n, setn] = myusestate(0)

const [m, setm] = myusestate(0)

return (

n: setn(n+1)}>+1

m: setm(m+1)}>+1

)}

上述實現的 myusestate 肯定不是 react.usestate 的具體實現**,但實現原理是一致的。myusestate 函式封裝了函式元件內的資料狀態,並對該狀態進行管理,以暴露出相關的操作介面的方式提供給函式元件使用。

這樣一來,函式元件就和其資料狀態分離了,函式元件只負責返回虛擬 dom 本身就可以了,對於資料狀態的管理完全交給其 「鉤」 住的 react.usestate hook 就可以了。

從上述的實現思路可以發現,react hooks 的實現其實是基於 全域性變數 和 閉包 原理實現的特殊函式。

但是,正是因為這樣的實現方式,限制了 react hooks 的使用必須是只在頂層呼叫hook,意思就是說 不要在迴圈,條件或巢狀函式中呼叫 hook,如果在 if 條件句中使用了 hook, 導致元件每次渲染生成時 react.usestate 語句的執行次數不對,就會打亂 index 的計數,從而導致資料維護的錯誤。

上述的實現原理依賴於 index 的正確計數,因此react 依賴於呼叫 hooks 的順序

react hooks 入門教程

你真的理解補碼嗎?

計算機數值運算的基礎硬體就是加法器,所以我們就從加法器講起。加法器是計算機數值計算的最基礎硬體單元,加減乘除都是以加法器為基礎實現的。加法器的構成如下圖所示,其中s是和數,c是進製。半加器電路是指對兩個輸入資料位相加,輸出乙個結果位和進製,沒有進製輸入的加法器電路。是實現兩個一位二進位制數的加法運算...

margin auto你真的理解麼?

含義 margin auto是具有強烈計算意味的關鍵字,用來計算元素對應方向應該獲得的剩餘空間大小 填充規則 1 如果一側定值,一側auto,則auto為剩餘空間大小 2 如果兩側均是auto,則平分剩餘空間 左邊距是20px,右邊距是80px。這裡son寬度是200px,容器是300px,總剩餘空...

margin auto你真的理解麼

含義 margin auto是具有強烈計算意味的關鍵字,用來計算元素對應方向應該獲得的剩餘空間大小 填充規則 1 如果一側定值,一側auto,則auto為剩餘空間大小 2 如果兩側均是auto,則平分剩餘空間 左邊距是20px,右邊距是80px。這裡son寬度是200px,容器是300px,總剩餘空...