欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React?Context源碼實現(xiàn)原理詳解

 更新時間:2022年10月11日 11:38:54   作者:flyzz177  
這篇文章主要為大家介紹了React?Context源碼實現(xiàn)原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

什么是 Context

目前來看 Context 是一個非常強大但是很多時候不會直接使用的 api。大多數(shù)項目不會直接使用 createContext 然后向下面?zhèn)鬟f數(shù)據(jù),而是采用第三方庫(react-redux)。

想想項目中是不是經(jīng)常會用到 @connect(...)(Comp) 以及 <Provider value={store}><App /></Provider>?

Context 提供了一個無需為每層組件手動添加 props,就能在組件樹間進行數(shù)據(jù)傳遞的方法。

一個頂層數(shù)據(jù),想要傳遞到某些深層組件,通過 props 逐層傳遞將會非常繁瑣,使用 Context 可避免顯式地通過組件樹逐層傳遞 props。

Context 使用示例

import React, { Component, createContext, useConText } from 'react'
const ColorContext = createContext(null)
const { Provider, Consumer } = ColorContext
console.log('ColorContext', ColorContext)
console.log('Provider', Provider)
console.log('Consumer', Consumer)
class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      color: 'red',
      background: 'cyan',
    }
  }
  render() {
    return <Provider value={this.state}>{this.props.children}</Provider>
  }
}
function Article({ children }) {
  return (
    <App>
      <h1>Context</h1>
      <p>hello world</p>
      {children}    </App>
  )
}
function Paragraph({ color, background }) {
  return (
    <div style={{ backgroundColor: background }}>
      <span style={{ color }}>text</span>
    </div>
  )
}
function TestContext() {
  return (
    <Article>
      <Consumer>{state => <Paragraph {...state} />}</Consumer>
    </Article>
  )
}
export default TestContext

頁面呈現(xiàn)出的效果

打印 ColorContext、Provider、Consumer

createContext

// createContext 可以讓我們實現(xiàn)狀態(tài)管理
// 還能夠解決傳遞 Props drilling 的問題
// 假如一個子組件需要父組件的一個屬性,但是中間間隔了好幾層,這就會出現(xiàn)開發(fā)和維護的一個成本。這時候就可以通過這個 API 來解決
function createContext(defaultValue, calculateChangedBits) {
  var context = {
    ?typeof: REACT_CONTEXT_TYPE,
    _calculateChangedBits: calculateChangedBits,
    // As a workaround to support multiple concurrent renderers, we categorize
    // some renderers as primary and others as secondary. We only expect
    // there to be two concurrent renderers at most: React Native (primary) and
    // Fabric (secondary); React DOM (primary) and React ART (secondary).
    // Secondary renderers store their context values on separate fields.
    // 以下兩個屬性是為了適配多平臺
    _currentValue: defaultValue,
    _currentValue2: defaultValue,
    // Used to track how many concurrent renderers this context currently
    // supports within in a single renderer. Such as parallel server rendering.
    _threadCount: 0,
    // These are circular
    Provider: null,
    Consumer: null
  };
  // 以下的代碼很簡單,就是在 context 上掛載 Provider 和 Consumer,讓外部去使用
  context.Provider = {
    ?typeof: REACT_PROVIDER_TYPE,
    _context: context
  };
  var Consumer = {
    ?typeof: REACT_CONTEXT_TYPE,
    _context: context,
    _calculateChangedBits: context._calculateChangedBits
  };
  context.Consumer = Consumer;
  context._currentRenderer = null;
  context._currentRenderer2 = null;
  return context;
}

react 包里面僅僅是生成了幾個對象,比較簡單,接下來看看它發(fā)揮作用的地方。

Consumer children 的匿名函數(shù)里面打 debugger。

查看調(diào)用棧

主要是 newChildren = render(newValue);,newChildrenConsumerchildren 被調(diào)用之后的返回值,render 就是 children,newValue 是從 Provider value 屬性的賦值。

newProps

newValue

接下來看 readContext 的實現(xiàn)

let lastContextDependency: ContextDependency<mixed> | null = null;
let currentlyRenderingFiber: Fiber | null = null;
// 在 prepareToReadContext 函數(shù)
currentlyRenderingFiber = workInProgress;
export function readContext<T>(
  context: ReactContext<T>,
  observedBits: void | number | boolean,
): T {
    let contextItem = {
      context: ((context: any): ReactContext<mixed>),
      observedBits: resolvedObservedBits,
      next: null,
    };
    if (lastContextDependency === null) {
      // This is the first dependency for this component. Create a new list.
      lastContextDependency = contextItem;
      currentlyRenderingFiber.contextDependencies = {
        first: contextItem,
        expirationTime: NoWork,
      };
    } else {
      // Append a new context item.
      lastContextDependency = lastContextDependency.next = contextItem;
    }
  }
  // isPrimaryRenderer 為 true,定義的就是 true
  // 實際就是一直會返回  context._currentValue
  return isPrimaryRenderer ? context._currentValue : context._currentValue2;
}

跳過中間,最后一句 return context._currentValue,而

就把頂層傳下來的 context 的值取到了

context 為什么從上層可以一直往下面?zhèn)鬟@點現(xiàn)在還沒有看懂,后面熟悉跨組件傳遞的實現(xiàn)之后再寫一篇文章解釋,囧。

Context 的設(shè)計非常特別

Provider Consumer 是 context 的兩個屬性。

  var context = {
    ?typeof: REACT_CONTEXT_TYPE,
    _currentValue: defaultValue,
    _currentValue2: defaultValue,
    Provider: null,
    Consumer: null
  };

Provider?typeofREACT_PROVIDER_TYPE,它帶有一個 _context 屬性,指向的就是 context 本身,也就是自己的兒子有一個屬性指向自己!??!

  context.Provider = {
    ?typeof: REACT_PROVIDER_TYPE,
    _context: context
  };

Consumer?typeofREACT_CONTEXT_TYPE,它帶也有一個 _context 屬性,也是自己的兒子有一個屬性指向自己?。?!

  var Consumer = {
    ?typeof: REACT_CONTEXT_TYPE,
    _context: context,
    _calculateChangedBits: context._calculateChangedBits
  };

所以可以做一個猜想, Provider 的 value 屬性賦予的新值肯定通過 _context 屬性傳到了 context 上,修改了 _currentValue。同樣,Consumer 也是依據(jù) _context 拿到了 context_currentValue,然后 render(newValue) 執(zhí)行 children 函數(shù)。

useContext

useContext 是 react hooks 提供的一個功能,可以簡化 context 值得獲取。

下面看使用代碼

import React, { useContext, createContext } from 'react'
const NameCtx = createContext({ name: 'yuny' })
function Title() {
  const { name } = useContext(NameCtx)
  return <h1># {name}</h1>
}
function App() {
  return (
    <NameCtx.Provider value={{ name: 'lxfriday' }}>
      <Title />
    </NameCtx.Provider>
  )
}
export default App

我么初始值給的是 {name: 'yuny'},實際又重新賦值 {name: 'lxfriday'},最終頁面顯示的是 lxfriday。

useContext 相關(guān)源碼

先看看 react 包中導(dǎo)出的 useContext

/** * useContext * @param Context {ReactContext} createContext 返回的結(jié)果 * @param unstable_observedBits {number | boolean | void} 計算新老 context 變化相關(guān)的,useContext() second argument is reserved for future  * @returns {*} 返回的是 context 的值 */
export function useContext<T>(
  Context: ReactContext<T>,  unstable_observedBits: number | boolean | void,
) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useContext(Context, unstable_observedBits);
}
// Invalid hook call. Hooks can only be called inside of the body of a function component. 
function resolveDispatcher() {
  const dispatcher = ReactCurrentDispatcher.current;
  return dispatcher;
}
/** * Keeps track of the current dispatcher. */
const ReactCurrentDispatcher = {
  /**   * @internal
   * @type {ReactComponent}   */
  current: (null: null | Dispatcher),
};

看看 Dispatcher,都是和 React Hooks 相關(guān)的。

再到 react-reconciler/src/ReactFiberHooks.js 中,有 HooksDispatcherOnMountInDEVHooksDispatcherOnMount,帶 InDEV 的應(yīng)該是在 development 環(huán)境會使用到的,不帶的是在 `production 會使用到。

const HooksDispatcherOnMount: Dispatcher = {
  readContext,
  useCallback: mountCallback,
  useContext: readContext,
  useEffect: mountEffect,
  useImperativeHandle: mountImperativeHandle,
  useLayoutEffect: mountLayoutEffect,
  useMemo: mountMemo,
  useReducer: mountReducer,
  useRef: mountRef,
  useState: mountState,
  useDebugValue: mountDebugValue,
};
HooksDispatcherOnMountInDEV = {
   // ... 
   useContext<T>(
      context: ReactContext<T>,
      observedBits: void | number | boolean,
    ): T {
      return readContext(context, observedBits);
    },
}

在上面 useContext 經(jīng)過 readContext 返回了 context 的值,readContext 在上面有源碼介紹。

debugger 查看調(diào)用棧

初始的 useContext

HooksDispatcherOnMountInDEV

readContext

經(jīng)過上面源碼的詳細分析, 大家對 context 的創(chuàng)建和 context 取值應(yīng)該了解了,context 設(shè)計真的非常妙!!

以上就是React Context源碼實現(xiàn)原理詳解的詳細內(nèi)容,更多關(guān)于React Context 源碼實現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React render核心階段深入探究穿插scheduler與reconciler

    React render核心階段深入探究穿插scheduler與reconciler

    這篇文章主要介紹了React render核心階段穿插scheduler與reconciler,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-11-11
  • 基于React實現(xiàn)一個todo打勾效果

    基于React實現(xiàn)一個todo打勾效果

    這篇文章主要為大家詳細介紹了如何基于React實現(xiàn)一個todo打勾效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • react拖拽react-beautiful-dnd一維數(shù)組二維數(shù)組拖拽功能

    react拖拽react-beautiful-dnd一維數(shù)組二維數(shù)組拖拽功能

    二維數(shù)組可以拖拽,但是不可以編輯+拖拽,如果想要實現(xiàn)編輯+拖拽,還是需要轉(zhuǎn)換成一維數(shù)組,本文給大家介紹react拖拽react-beautiful-dnd的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2024-03-03
  • React18新增特性released的使用

    React18新增特性released的使用

    本文主要介紹了React18新增特性released的使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • React快速入門教程

    React快速入門教程

    本文主要介紹了React的相關(guān)知識,具有一定的參考價值,下面跟著小編一起來看下吧
    2017-01-01
  • 使用useEffect模擬組件生命周期

    使用useEffect模擬組件生命周期

    這篇文章主要介紹了使用useEffect模擬組件生命周期,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 如何在react項目中做公共配置文件

    如何在react項目中做公共配置文件

    這篇文章主要介紹了如何在react項目中做公共配置文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 如何在React項目中使用AntDesign

    如何在React項目中使用AntDesign

    我們在后臺管理系統(tǒng)React項目開發(fā)中會有Table表格、Form表單、List列表、Button按鈕等組件,這個時候我們可以使用AntDesign來減少開發(fā)中不必要的樣式問題,本文就介紹了eact項目中使用AntDesign,感興趣的可以了解一下
    2022-04-04
  • React?createRef循環(huán)動態(tài)賦值ref問題

    React?createRef循環(huán)動態(tài)賦值ref問題

    這篇文章主要介紹了React?createRef循環(huán)動態(tài)賦值ref問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • React Native第三方平臺分享的實例(Android,IOS雙平臺)

    React Native第三方平臺分享的實例(Android,IOS雙平臺)

    本篇文章主要介紹了React Native第三方平臺分享的實例(Android,IOS雙平臺),具有一定的參考價值,有興趣的可以了解一下
    2017-08-08

最新評論