中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

關于useState的知識點有哪些

發布時間:2021-10-28 15:18:33 來源:億速云 閱讀:210 作者:iii 欄目:web開發

本篇內容介紹了“關于useState的知識點有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

hook如何保存數據

FunctionComponent的render本身只是函數調用。

那么在render內部調用的hook是如何獲取到對應數據呢?

比如:

  •  useState獲取state

  •  useRef獲取ref

  •  useMemo獲取緩存的數據

答案是:

每個組件有個對應的fiber節點(可以理解為虛擬DOM),用于保存組件相關信息。

每次FunctionComponent render時,全局變量currentlyRenderingFiber都會被賦值為該FunctionComponent對應的fiber節點。

所以,hook內部其實是從currentlyRenderingFiber中獲取狀態信息的。

多個hook如何獲取數據

我們知道,一個FunctionComponent中可能存在多個hook,比如:

function App() {    // hookA    const [a, updateA] = useState(0);    // hookB   const [b, updateB] = useState(0);    // hookC    const ref = useRef(0);    return <p></p>;  }

那么多個hook如何獲取自己的數據呢?

答案是:

currentlyRenderingFiber.memoizedState中保存一條hook對應數據的單向鏈表。

對于如上例子,可以理解為:

const hookA = {    // hook保存的數據    memoizedState: null,    // 指向下一個hook    next: hookB    // ...省略其他字段  }; hookB.next = hookC;  currentlyRenderingFiber.memoizedState = hookA;

當FunctionComponent render時,每執行到一個hook,都會將指向currentlyRenderingFiber.memoizedState鏈表的指針向后移動一次,指向當前hook對應數據。

這也是為什么React要求hook的調用順序不能改變(不能在條件語句中使用hook) &mdash;&mdash; 每次render時都是從一條固定順序的鏈表中獲取hook對應數據的。

關于useState的知識點有哪些

useState執行流程

我們知道,useState返回值數組第二個參數為改變state的方法。

在源碼中,他被稱為dispatchAction。

每當調用dispatchAction,都會創建一個代表一次更新的對象update:

const update = {    // 更新的數據    action: action,    // 指向下一個更新    next: null  };

對于如下例子

function App() {    const [num, updateNum] = useState(0);    function increment() {      updateNum(num + 1);    }    return <p onClick={increment}>{num}</p>;  }

調用updateNum(num + 1),會創建:

const update = {    // 更新的數據    action: 1,    // 指向下一個更新    next: null    // ...省略其他字段  };

如果是多次調用dispatchAction,例如:

function increment() {    // 產生update1    updateNum(num + 1);    // 產生update2    updateNum(num + 2);    // 產生update3    updateNum(num + 3);  }

那么,update會形成一條環狀鏈表。

update3 --next--> update1    ^                 |    |               update2    |______next_______|

這條鏈表保存在哪里呢?

既然這條update鏈表是由某個useState的dispatchAction產生,那么這條鏈表顯然屬于該useState hook。

我們繼續補充hook的數據結構。

const hook = {    // hook保存的數據    memoizedState: null,    // 指向下一個hook    next: hookForB    // 本次更新以baseState為基礎計算新的state    baseState: null,    // 本次更新開始時已有的update隊列    baseQueue: null,    // 本次更新需要增加的update隊列    queue: null,  };

其中,queue中保存了本次更新update的鏈表。

在計算state時,會將queue的環狀鏈表剪開掛載在baseQueue最后面,baseQueue基于baseState計算新的state。

關于useState的知識點有哪些

在計算state完成后,新的state會成為memoizedState。

為什么更新不基于memoizedState而是baseState,是因為state的計算過程需要考慮優先級,可能有些update優先級不夠被跳過。所以memoizedState并不一定和baseState相同。更詳細的解釋見React技術揭秘[1]

回到我們開篇第一個問題:

function App() {    const [num, updateNum] = useState(0);    window.updateNum = updateNum;    return num;  }

調用window.updateNum(1)可以將視圖中的0更新為1么?

我們需要看看這里的updateNum方法的具體實現:

updateNum === dispatchAction.bind(null, currentlyRenderingFiber, queue);

可見,updateNum方法即綁定了currentlyRenderingFiber與queue(即hook.queue)的dispatchAction。

上文已經介紹,調用dispatchAction的目的是生成update,并插入到hook.queue鏈表中。

既然queue作為預置參數已經綁定給dispatchAction,那么調用dispatchAction就步僅局限在FunctionComponent內部了。

update的action

第二個問題

function App() {    const [num, updateNum] = useState(0);    function increment() {      setTimeout(() => {        updateNum(num + 1);      }, 1000);    }    return <p onClick={increment}>{num}</p>;  }

在1秒內快速點擊p5次,視圖上顯示為幾?

我們知道,調用updateNum會產生update,其中傳參會成為update.action。

在1秒內點擊5次。在點擊第五次時,第一次點擊創建的update還沒進入更新流程,所以hook.baseState還未改變。

那么這5次點擊產生的update都是基于同一個baseState計算新的state,并且num變量也還未變化(即5次update.action(即num + 1)為同一個值)。

所以,最終渲染的結果為1。

useState與useReducer

那么,如何5次點擊讓視圖從1逐步變為5呢?

由以上知識我們知道,需要改變baseState或者action。

其中baseState由React的更新流程決定,我們無法控制。

但是我們可以控制action。

action不僅可以傳值,也可以傳函數。

// action為值  updateNum(num + 1);  // action為函數  updateNum(num => num + 1);

在基于baseState與update鏈表生成新state的過程中:

let newState = baseState;  let firstUpdate = hook.baseQueue.next;  let update = firstUpdate; // 遍歷baseQueue中的每一個update  do {    if (typeof update.action === 'function') {      newState = update.action(newState);    } else {      newState = action;    }  } while (update !== firstUpdate)

可見,當傳值時,由于我們5次action為同一個值,所以最終計算的newState也為同一個值。

而傳函數時,newState基于action函數計算5次,則最終得到累加的結果。

如果這個例子中,我們使用useReducer而不是useState,由于useReducer的action始終為函數,所以不會遇到我們例子中的問題。

事實上,useState本身就是預置了如下reducer的useReducer。

function basicStateReducer(state, action) {    return typeof action === 'function' ? action(state) : action;  }

“關于useState的知識點有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

淮滨县| 潍坊市| 泰州市| 兴宁市| 双牌县| 阿勒泰市| 横峰县| 福贡县| 胶南市| 越西县| 固安县| 淮滨县| 北流市| 康乐县| 绥中县| 凌海市| 中阳县| 安徽省| 海城市| 葫芦岛市| 淄博市| 新乡县| 潜山县| 高阳县| 门头沟区| 曲阜市| 宜州市| 汉沽区| 珠海市| 东城区| 凭祥市| 新源县| 永顺县| 天峻县| 建昌县| 南澳县| 三穗县| 吉木萨尔县| 新郑市| 美姑县| 拉萨市|