React的React.createContext()源碼解析(四)


一.產生context原因

從父組件直接傳值到孫子組件,而不必一層一層的通過props進行傳值,相比較以前的那種傳值更加的方便、簡介。

二.context的實現方式

新版本(React16.x后)

//創建兩個組件 Provider,Consumer
//let {Provider,Consumer}=React.createContext(defaultValue); //defaultValue可以設置共享的默認數據 當Provider不存在的時候 defaultValue生效
const { Provider, Consumer } = React.createContext({ theme: "green" })
class MessageList extends React.Component {
  render() {
    //Procider組件遍歷子組件,並且有一個屬性value用來提供數據
    return (
      <Provider value={{ theme: "pink" }}>
        <Content />
      </Provider>
    )
  }
}
//中間組件
function Content() {
  return (
    <div>
      <Button />
    </div>
  )
}
//接收組件,如果子組件是Consumer的話,將value作為參數值,傳遞給新創建的Consumer渲染一個函數組件
function Button() {
  return (
    <Consumer>
      {({ theme }) => (
        <button
          style={{ backgroundColor: theme }}>
          Toggle Theme
        </button>
      )}
    </Consumer>
  )
}

注意:將undefined傳遞給<Provider>value時,createContext中的defaultValue不會生效,Consumervalue顯示空值 

三.React.createContext()源碼解析

    //calculateChangedBits方法,使用Object.is()計算新老context變化
//defaultValue 當Provider組件屬性value不存在時 會使用默認值defaultValue
function createContext(defaultValue, calculateChangedBits) { if (calculateChangedBits === undefined) { calculateChangedBits = null; } else { { !(calculateChangedBits === null || typeof calculateChangedBits === 'function') ? warningWithoutStack$1(false, 'createContext: Expected the optional second argument to be a ' + 'function. Instead received: %s', calculateChangedBits) : void 0; } } var context = { $$typeof: REACT_CONTEXT_TYPE, //context的$$typeof在createElement中的type中的type對象中存儲 _calculateChangedBits: calculateChangedBits,//計算新老context變化 //_currentValue和_currentValue2作用一樣,只是作用平台不同 _currentValue: defaultValue, //Provider的value屬性 _currentValue2: defaultValue, _threadCount: 0, //用來追蹤context的並發渲染器數量 // These are circular Provider: null, //提供組件 Consumer: null //應用組件 }; //context.Provider的_context指向context對象 context.Provider = { $$typeof: REACT_PROVIDER_TYPE, _context: context }; var hasWarnedAboutUsingNestedContextConsumers = false; var hasWarnedAboutUsingConsumerProvider = false; { // A separate object, but proxies back to the original context object for // backwards compatibility. It has a different $$typeof, so we can properly // warn for the incorrect usage of Context as a Consumer. var Consumer = { $$typeof: REACT_CONTEXT_TYPE, _context: context, _calculateChangedBits: context._calculateChangedBits //計算新老context變化 }; // $FlowFixMe: Flow complains about not setting a value, which is intentional here Object.defineProperties(Consumer, { Provider: { get: function () { if (!hasWarnedAboutUsingConsumerProvider) { hasWarnedAboutUsingConsumerProvider = true; warning$1(false, 'Rendering <Context.Consumer.Provider> is not supported and will be removed in ' + 'a future major release. Did you mean to render <Context.Provider> instead?'); } return context.Provider; }, set: function (_Provider) { context.Provider = _Provider; } }, _currentValue: { get: function () { return context._currentValue; }, set: function (_currentValue) { context._currentValue = _currentValue; } }, _currentValue2: { get: function () { return context._currentValue2; }, set: function (_currentValue2) { context._currentValue2 = _currentValue2; } }, _threadCount: { get: function () { return context._threadCount; }, set: function (_threadCount) { context._threadCount = _threadCount; } }, Consumer: { get: function () { if (!hasWarnedAboutUsingNestedContextConsumers) { hasWarnedAboutUsingNestedContextConsumers = true; warning$1(false, 'Rendering <Context.Consumer.Consumer> is not supported and will be removed in ' + 'a future major release. Did you mean to render <Context.Consumer> instead?'); } return context.Consumer; } } }); // $FlowFixMe: Flow complains about missing properties because it doesn't understand defineProperty context.Consumer = Consumer; } { context._currentRenderer = null; context._currentRenderer2 = null; } //返回一個context對象 return context; }

解析:

1._currentValue 用來記錄Provider/Consumer的value值 默認為defaultValue

2.在context設置Provider和Consumer屬性值

  • Provider屬性
  context.Provider = {
    $$typeof: REACT_PROVIDER_TYPE,
     _context: context
  };

表示給context的provider設置屬性值 如果我們需要設置當前Provider上的value值 則直接使用context.Provider._context._currentValue進行設置 

  • Consumer屬性
  var Consumer = {
     $$typeof: REACT_CONTEXT_TYPE,
     _context: context,
     _calculateChangedBits: context._calculateChangedBits
   };
  context.Consumer = Consumer;

表示給context設置Consumer設置屬性值 如果我們需要獲取當前通過Provider上的value值 則直接通過自身的Consumer組件的context.Consumer._context._currentValue獲取value值

3.return context對象

返回的context對象中包含Provider/Consumer/_currentValue/_calculateChangedBits計算新老context變化等值 

const { Provider, Consumer } = React.createContext({ theme: "green" })

通過React.createContext調用createContext方法 獲取context中的Provider和Consumer組件對象 當調用React.createElement(type,config,..)作為type值進行傳遞

返回的context內容圖解:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM