React.createContext 源码思考

https://github.com/facebook/react/blob/master/packages/react/src/ReactContext.js

export function createContext<T>(
  defaultValue: T,
  calculateChangedBits: ?(a: T, b: T) => number, // 一个方法,用来计算新老context变化(通过 Object.is() 计算新老context的差异)。
): ReactContext<T> {
  if (calculateChangedBits === undefined) {
    calculateChangedBits = null;
  } else { }
const context: ReactContext<T> = {
    $$typeof: REACT_CONTEXT_TYPE, // 与ReactElement的$$typeof不一样 是作为createElement中的属性type中的对象进行存储的。
    _calculateChangedBits: calculateChangedBits,
    /*
    	作为支持多个并发渲染器的解决方法,我们将一些渲染器分类为主要渲染器,将其他渲染器分类为辅助渲染器。
    	
    	我们只希望最多有两个并发渲染器:React Native(主要)和Fabric(次要);
    	React DOM(主要)和React ART(次要)。
    	辅助渲染器将自己的context的value存储在单独的字段中。
    	
    	<Provider value={xxx}>中的value就是赋值给_currentValue的,
    	也就是说_currentValue和_currentValue2作用是一样的,只是分别给主渲染器和辅助渲染器使用
    	_currentValue和_currentValue2作用一样,只是作用平台不同
    */
    // 用来记录Prvoider上面提供的value有变化的情况下,就会更新到这个_currentValue上面,就是用来记录最新的context的值的
    _currentValue: defaultValue,
    _currentValue2: defaultValue,
    _threadCount: 0, // 用来追踪该context的并发渲染器的数量
    Provider: (null: any),
    Consumer: (null: any),
  };
 
  context.Provider = {
    $$typeof: REACT_PROVIDER_TYPE,
    _context: context,
  };
  
  let hasWarnedAboutUsingNestedContextConsumers = false;
  let hasWarnedAboutUsingConsumerProvider = false;
  let hasWarnedAboutDisplayNameOnConsumer = false;

  if (__DEV__) {
    const Consumer = {
      $$typeof: REACT_CONTEXT_TYPE,
      _context: context,
      _calculateChangedBits: context._calculateChangedBits,
    };
    // $FlowFixMe: Flow complains about not setting a value, which is intentional here
    Object.defineProperties(Consumer, {
      Provider: {
        get() {
          if (!hasWarnedAboutUsingConsumerProvider) {
            hasWarnedAboutUsingConsumerProvider = true;
            console.error(
              '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(_Provider) {
          context.Provider = _Provider;
        },
      },
      _currentValue: {
        get() {
          return context._currentValue;
        },
        set(_currentValue) {
          context._currentValue = _currentValue;
        },
      },
      _currentValue2: {
        get() {
          return context._currentValue2;
        },
        set(_currentValue2) {
          context._currentValue2 = _currentValue2;
        },
      },
      _threadCount: {
        get() {
          return context._threadCount;
        },
        set(_threadCount) {
          context._threadCount = _threadCount;
        },
      },
      Consumer: {
        get() {
          if (!hasWarnedAboutUsingNestedContextConsumers) {
            hasWarnedAboutUsingNestedContextConsumers = true;
            console.error(
              '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;
        },
      },
      displayName: {
        get() {
          return context.displayName;
        },
        set(displayName) {
          if (!hasWarnedAboutDisplayNameOnConsumer) {
            console.warn(
              'Setting `displayName` on Context.Consumer has no effect. ' +
                "You should set it directly on the context with Context.displayName = '%s'.",
              displayName,
            );
            hasWarnedAboutDisplayNameOnConsumer = true;
          }
        },
      },
    });
    // $FlowFixMe: Flow complains about missing properties because it doesn't understand defineProperty   
    context.Consumer = Consumer;
  } else {
    context.Consumer = context;
  }

  if (__DEV__) {
    context._currentRenderer = null;
    context._currentRenderer2 = null;
  }

  return context;
}

新旧对比源码

export function calculateChangedBits<T>(
  context: ReactContext<T>, // context
  newValue: T,
  oldValue: T,
) {
  if (is(oldValue, newValue)) { // Object.is() 
    // No change
    return 0;
  } else {
    const changedBits =
      typeof context._calculateChangedBits === 'function'
        ? context._calculateChangedBits(oldValue, newValue)
        : MAX_SIGNED_31_BIT_INT;

    if (__DEV__) {
      if ((changedBits & MAX_SIGNED_31_BIT_INT) !== changedBits) {
        console.error(
          'calculateChangedBits: Expected the return value to be a ' +
            '31-bit integer. Instead received: %s',
          changedBits,
        );
      }
    }
    // 返回 被改变的值(改变了);没有给改变返回 0
    return changedBits | 0;
  }
}

超级全的解析

猜你喜欢

转载自blog.csdn.net/qq_42387542/article/details/107706096
今日推荐