最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ReactDOM 隱藏特性詳解

 更新時間:2022年09月01日 15:45:17   作者:貨拉拉技術(shù)  
這篇文章主要為大家介紹了ReactDOM 隱藏特性詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

有過 React 經(jīng)驗的開發(fā)者可能都使用過 React DevTools。

DevTools 提供了豐富的能力:展示組件樹,組件的 props 與組件中 hook 的值。

React DevTools 是如何檢測當(dāng)前網(wǎng)頁是否使用 React 以及是如何獲取組件相關(guān)的眾多數(shù)據(jù)呢?

React DevTools 的原理

打開 ReactDOM 代碼時,用 devtools 為關(guān)鍵字搜索,你會發(fā)現(xiàn)許多與 React DevTools 相關(guān)的代碼。

function injectInternals(internals) {
  if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
    // No DevTools
    return false;
  }
  var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__;
  try {
    rendererID = hook.inject(internals); // We have successfully injected, so now it is safe to set up hooks.
    injectedHook = hook;
  } catch (err) {
    // ...
  } // DevTools exists
}

在瀏覽器控制臺輸入 __REACT_DEVTOOLS_GLOBAL_HOOK__ 詳細看一下這個對象。

這個對象十分復(fù)雜,以下的幾個方法倒是很值得關(guān)注。

onCommitFiberRoot

onCommitFiberUnmount

onPostCommitFiberRoot

渲染階段

從名稱來看,上面這幾個方法與 ReactDOM 的渲染密切相關(guān)。

ReactDOM 在特定的階段會調(diào)用這些的方法,比如:onCommitFiberRoot。

function onCommitRoot(root, priorityLevel) {
  if (injectedHook && typeof injectedHook.onCommitFiberRoot === 'function') {
    try {
      // ...
      injectedHook.onCommitFiberRoot(rendererID, root, priorityLevel, didError);
    } catch (err) {}
  }
}

正是借助 __REACT_DEVTOOLS_GLOBAL_HOOK__,React DevTools 便與 ReactDOM 建立起了聯(lián)系,從而擁有獲取組件眾多信息的能力。

FiberRoot/FiberNode

在新的 React 架構(gòu)下,會先把 Virtual DOM 轉(zhuǎn)成 FiberNode,然后再渲染 FiberNode。

onCommitFiberRoot 等方法中的傳遞的數(shù)據(jù)正是 FiberNode。

FiberNode 的結(jié)構(gòu)是比較復(fù)雜的,可以簡化為如下的結(jié)構(gòu):

interface ReactFiberRootNode {
  current: ReactFiberNode;
  // ...
}
interface ReactFiberNode {
  tag: number;
  stateNode: null | HTMLElement; // dom 節(jié)點
  memoizedProps?: Record<string, any>; // props
  memoizedState: ClassComponentState | HookLinkedQueue | null; // hooks
  child?: ReactFiberNode;
  sibling?: ReactFiberNode;
  return: ReactFiberNode; // parent
  // ...
}

從上面的結(jié)構(gòu)可以看出,F(xiàn)iberNode 包含了非常多與組件相關(guān)的信息。

stateNode 為組件對應(yīng)真實的 DOM 節(jié)點,memoizedProps 為組件的 props。

當(dāng)組件為函數(shù)式組件時,tag 為 0,memoizedState 保存了組件中的 hooks 信息。

當(dāng)組件為類組件時,tag 為 1,memoizedState 則是組件的 state。

如下圖所示,F(xiàn)iberNode 節(jié)點形成一個鏈表結(jié)構(gòu)。

只要能找到組件對應(yīng)的 FiberNode,我們便可以做到在運行期間以無侵入的方法獲取組件的眾多信息。比如:通過 FiberNode 進行遍歷,實現(xiàn) findNativeNodesForFiber 方法,用以查找其對應(yīng)的真實 DOM 節(jié)點。

function findNativeNodesForFiber(node?: ReactFiberNode) {
  // ...
  // 先遍歷 child
  const { child } = node;
  collectStateNode();
  // 再遍歷所有的 sibling
  let current = child?.sibling;
  while (current) {
    collectStateNode();
    current = current.sibling;
  }
  // ...
}

React DevTools 中審查元素功能正是基于類似的原理去實現(xiàn)。

memoizedState 與 React Hooks

上文中提到當(dāng)組件為函數(shù)式組件時,memoizedState 保存了 React Hooks 相關(guān)的信息。與 FiberNode 類似,React Hooks 也形成一個鏈表。

export interface HookLinkedQueue {
  memoizedState: any; // 渲染時的值
  next: HookLinkedQueue | null;
  // ...
}

React Hook 將其數(shù)據(jù)都保存在 memoizedState 上。比如對于 useRef 來說,ref.current 值就是 memoizedState。類似的,可以實現(xiàn) inspectSomeHooksOfFiber 來獲取組件內(nèi)使用特定 hook 中保存的值。

function inspectRefHooksOfFiber(node: ReactFiberNode) {
  let current: HookLinkedQueue | null = node.memoizedState;
  while (current) {
    retrieveValue(current);
    current = current.next;
  }
}

實踐:突破 useDebugValue 的限制

useDebugValue 是 React 內(nèi)置的一個 hook,用以在 React DevTools 中顯示自定義 hook 的標(biāo)簽。它的限制是只能在 hook 中使用。借助前文介紹的知識點,我們可以實現(xiàn)一個增加版的 useDebugValue,你可以像普通的 hook 一樣來使用它,沒有其他限制。

useDebugValueAnywhere 的實現(xiàn)

useDebugValueAnywhere 實現(xiàn)比較簡單,name 表明數(shù)據(jù)的名稱,用一個特殊的 ref 對象來存儲 debug 相關(guān)的數(shù)據(jù)。

export function useDebugValueAnywhere(name: string, data: any) {
  const ref = useRef({
    [DebugHookKey]: {
      name,
      data,
    },
  });
  // ...
}

特定的 devtools

參考 React DevTools 的邏輯,在 __REACT_DEVTOOLS_GLOBAL_HOOK__ 中注入我們的 onCommitFiberRoot 方法,從而確保 ReactDOM 每次渲染時,能獲取最新的 FiberNode。

currentHook.onCommitFiberRoot = function (...args) {
  handleCommitFiberRoot(...args); // 注入
  oldOnCommitFiberRoot.apply(this, args);
};

接下來便是對 FiberNode 進行遍歷。在遍歷的過程中,檢查每個 FiberNode 中 memoizedState 鏈表,檢測組件的 hooks 中是否用到了 useDebugValueAnywhere。

如果存在,就將值 FiberNode 與 hook 中的值保存起來。

{
  visitFiberNode(node?: ReactFiberNode) {
    if (!node) return;
    this.inspectFiber(node);
    this.visitFiberNode(node.child);
    let { sibling } = node;
    while (sibling) {
      this.visitFiberNode(sibling);
      sibling = sibling.sibling;
    }
  }
}

剩下的工作就是考慮以何種形式去展示收集到的 debug 信息。在 PC 端可以直接輸出數(shù)據(jù)到控制臺;在移動端 vConsole 使用較多,那么就可以基于 vConsole 開發(fā)一個插件,實現(xiàn)一個極簡版的 React DevTools,專門用以展示這些信息。

完整的代碼。

總結(jié)

本文剖析了 React DevTools 的原理,介紹隱藏在 ReactDOM 中的一些特性,并帶領(lǐng)大家熟悉了一下 React Fiber 架構(gòu)?;谏鲜鲈恚梢蚤_發(fā)一個增加版的 useDebugValue。

由于本文介紹的特性并非公開的 API,沒有兼容性。當(dāng) React/ReactDOM 版本升級時,還需要再做適配,因此只適合用來開發(fā) DevTools 之類的工具,不推薦業(yè)務(wù)開發(fā)使用。

以上就是ReactDOM 隱藏特性詳解的詳細內(nèi)容,更多關(guān)于ReactDOM 隱藏特性的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用webpack5從0到1搭建一個react項目的實現(xiàn)步驟

    使用webpack5從0到1搭建一個react項目的實現(xiàn)步驟

    這篇文章主要介紹了使用webpack5從0到1搭建一個react項目的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • React中的setState使用細節(jié)和原理解析(最新推薦)

    React中的setState使用細節(jié)和原理解析(最新推薦)

    這篇文章主要介紹了React中的setState使用細節(jié)和原理解析(最新推薦),前面我們有使用過setState的基本使用, 接下來我們對setState使用進行詳細的介紹,需要的朋友可以參考下
    2022-12-12
  • 如何不使用eject修改create-react-app的配置

    如何不使用eject修改create-react-app的配置

    許多剛開始接觸create-react-app框架的同學(xué),不免都會有個疑問:如何在不執(zhí)行eject操作的同時,修改create-react-app的配置。
    2021-04-04
  • 一文帶你了解React中的并發(fā)機制

    一文帶你了解React中的并發(fā)機制

    React 18.2.0 引入了一系列并發(fā)機制的新特性,旨在幫助各位開發(fā)者更好地控制和優(yōu)化應(yīng)用程序的性能和用戶體驗,下面我們就來看看如何利用這些新特性構(gòu)建更高效、更響應(yīng)式的應(yīng)用程序吧
    2024-03-03
  • axios請求響應(yīng)數(shù)據(jù)加解密封裝實現(xiàn)詳解

    axios請求響應(yīng)數(shù)據(jù)加解密封裝實現(xiàn)詳解

    這篇文章主要為大家介紹了axios請求響應(yīng)數(shù)據(jù)加解密封裝實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • react-router中Link標(biāo)簽和a標(biāo)簽有什么區(qū)別

    react-router中Link標(biāo)簽和a標(biāo)簽有什么區(qū)別

    本文主要介紹了react-router中Link標(biāo)簽和a標(biāo)簽有什么區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • React報錯之Object?is?possibly?null的問題及解決方法

    React報錯之Object?is?possibly?null的問題及解決方法

    這篇文章主要介紹了React報錯之Object?is?possibly?null的問題,造成 "Object is possibly null"的錯誤是因為useRef()鉤子可以傳遞一個初始值作為參數(shù),而我們傳遞null作為初始值,本文給大家分享詳細解決方法,需要的朋友可以參考下
    2022-07-07
  • react項目升級報錯,babel報錯,.babelrc配置兼容等問題及解決

    react項目升級報錯,babel報錯,.babelrc配置兼容等問題及解決

    這篇文章主要介紹了react項目升級報錯,babel報錯,.babelrc配置兼容等問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • js中自定義react數(shù)據(jù)驗證組件實例詳解

    js中自定義react數(shù)據(jù)驗證組件實例詳解

    我們在做前端表單提交時,經(jīng)常會遇到要對表單中的數(shù)據(jù)進行校驗的問題。這篇文章主要介紹了js中自定義react數(shù)據(jù)驗證組件 ,需要的朋友可以參考下
    2018-10-10
  • React中常用的一些鉤子函數(shù)總結(jié)

    React中常用的一些鉤子函數(shù)總結(jié)

    這篇文章給大家總結(jié)了React中常用的一些鉤子函數(shù),文中通過代碼示例給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-01-01

最新評論

诸暨市| 深水埗区| 荆州市| 湟中县| 抚州市| 尼玛县| 永宁县| 多伦县| 京山县| 柘城县| 平乐县| 平原县| 新余市| 绍兴市| 阳春市| 观塘区| 潜山县| 盈江县| 金华市| 九寨沟县| 崇左市| 家居| 凤山市| 西藏| 东城区| 墨玉县| 女性| 玛多县| 涡阳县| 临城县| 河西区| 晋宁县| 本溪| 元朗区| 交口县| 秀山| 苍梧县| 新河县| 大渡口区| 高密市| 渭南市|