资讯专栏INFORMATION COLUMN

React源码解析之React.createContext()

booster / 3071人阅读

摘要:我们只希望最多有两个并发渲染器主要和次要主要和次要。辅助渲染器将自己的的存储在多带带的字段中。

前言:
由于childContextReact17中会被废弃,所以不去分析它了,主要是新 API— —createContext()的讲解

一、React.createContext()

作用:
方便祖先组件与后代组件(中间隔了好多层组件)传值

使用:
context.js:

import React from "react";

const contextTestOne={
  name:"chen",
  length:22,
}

export const wrapContext=React.createContext(contextTestOne.name)

祖先组件:

import { wrapContext } from "@/utils/context";

const Father=props=>{
  return (
     
)
}

子孙组件:

import { wrapContext } from "@/utils/context";

const getProviderValue=()=>{
  return {value=>{value}}
}

const Child=props=>{
return (
    getProviderValue()
  );
}

结果:

注意:
undefined传递给value时,createContext中的defaultValue不会生效,Consumervalue显示空值

React 官方文档:
https://zh-hans.reactjs.org/docs/context.html#contextprovider

源码:

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import {REACT_PROVIDER_TYPE, REACT_CONTEXT_TYPE} from "shared/ReactSymbols";

import type {ReactContext} from "shared/ReactTypes";

import warningWithoutStack from "shared/warningWithoutStack";
import warning from "shared/warning";

export function createContext(
  defaultValue: T,
  //使用Object.is()计算新老context的差异
  calculateChangedBits: ?(a: T, b: T) => number,
): ReactContext {
  if (calculateChangedBits === undefined) {
    calculateChangedBits = null;
  } else {
    //不看
    if (__DEV__) {
      warningWithoutStack(
        calculateChangedBits === null ||
          typeof calculateChangedBits === "function",
        "createContext: Expected the optional second argument to be a " +
          "function. Instead received: %s",
        calculateChangedBits,
      );
    }
  }

  const context: ReactContext = {
    //还是那句话,ReactContext中的$$typeof是
    // 作为createElement中的属性type中的对象进行存储的,并不是ReactElement的$$typeof
    $$typeof: REACT_CONTEXT_TYPE,
    _calculateChangedBits: calculateChangedBits,
    //作为支持多个并发渲染器的解决方法,我们将一些渲染器分类为主要渲染器,将其他渲染器分类为辅助渲染器。
    // As a workaround to support multiple concurrent renderers, we categorize
    // some renderers as primary and others as secondary.

    //我们只希望最多有两个并发渲染器:React Native(主要)和Fabric(次要);
    // React DOM(主要)和React ART(次要)。
    // 辅助渲染器将自己的context的value存储在多带带的字段中。
    // 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.

    //中的value就是赋值给_currentValue的

    //也就是说_currentValue和_currentValue2作用是一样的,只是分别给主渲染器和辅助渲染器使用
    _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.

    //用来追踪该context的并发渲染器的数量
    _threadCount: 0,
    // These are circular
    Provider: (null: any),
    Consumer: (null: any),
  };
  //const obj={}
  //obj.provider._obj = obj
  context.Provider = {
    $$typeof: REACT_PROVIDER_TYPE,
    _context: context,
  };

  let hasWarnedAboutUsingNestedContextConsumers = false;
  let hasWarnedAboutUsingConsumerProvider = false;
  //不看
  if (__DEV__) {
    // 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.
    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;
            warning(
              false,
              "Rendering  is not supported and will be removed in " +
                "a future major release. Did you mean to render  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;
            warning(
              false,
              "Rendering  is not supported and will be removed in " +
                "a future major release. Did you mean to render  instead?",
            );
          }
          return context.Consumer;
        },
      },
    });
    // $FlowFixMe: Flow complains about missing properties because it doesn"t understand defineProperty
    context.Consumer = Consumer;
  }

  else {
    //const obj={}
    //obj.consumer=obj
    //也就是Consumber对象指向React.Context对象

    //在进行渲染时,为了保证Consumer拿到最新的值,
    //直接让Consumer=React.Context,
    // React.Context中的_currentValue已经被的value给赋值了
    //所以Consumer能立即拿到最新的值
    context.Consumer = context;
  }
  //不看
  if (__DEV__) {
    context._currentRenderer = null;
    context._currentRenderer2 = null;
  }

  return context;
}

解析:
不看__DEV__的话,还是挺简单的,需要注意的是context.Consumer = context,让等于React.context,这样能立即拿到提供的最新值

二、为什么要弃用childContext
因为childContext对下层的组件影响太大了,即使子孙组件没有用到childContext,子孙组件仍然要进行Update,严重影响了性能

(完)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106160.html

相关文章

  • React 新特性讲解及实例(一)

    摘要:接收一个属性,这个组件会让后代组件统一提供这个变量值。因此对于同一个对象而言,一定是后代元素。解决方法就是把内联函数提取出来,如下讲了这么多,我们还没有讲到其实我们已经讲完了的工作原理了。 本节主要讲解以下几个新的特性: Context ContextType lazy Suspense 错误边界(Error boundaries) memo 想阅读更多优质文章请猛戳GitHub博...

    Betta 评论0 收藏0
  • [ 一起学React系列 -- 4 ] 透传的Context

    摘要:官方对的介绍是意思就是提供了一种通过组件树传递数据的方法,而无需在每个级别手动传递。这也是基于重要物证哈哈实例使用学习技术最终是要有产出的。依然被视作一个组件,不过不同的是它的子组件必须是一个方法并且该方法接收当前对象并最终返回一个节点。 抛转引玉 通过上一篇的科普我们知道如果父节点需要向子节点传递数据,那么就得通过Props来实现;那么摆在我们眼前的就有一个问题了:现有N个节点并且它...

    firim 评论0 收藏0
  • [源码阅读]高性能和可扩展的React-Redux

    摘要:到主菜了,先看它的一看,我们应该有个猜测,这货是个高阶函数。可能有点绕,但就是这么一个个高阶函数组成的,后面会详细说。定义了一个处理函数和高阶函数执行次的方法,这个方法比上面的复杂在于它需要检测参数是否订阅了。 注意:文章很长,只想了解逻辑而不深入的,可以直接跳到总结部分。 初识 首先,从它暴露对外的API开始 ReactReduxContext /* 提供了 React.creat...

    shuibo 评论0 收藏0
  • 精读《React16 新特性》

    摘要:引言于发布版本,时至今日已更新到,且引入了大量的令人振奋的新特性,本文章将带领大家根据更新的时间脉络了解的新特性。其作用是根据传递的来更新。新增等指针事件。 1 引言 于 2017.09.26 Facebook 发布 React v16.0 版本,时至今日已更新到 React v16.6,且引入了大量的令人振奋的新特性,本文章将带领大家根据 React 更新的时间脉络了解 React1...

    Nosee 评论0 收藏0
  • React Hooks 解析(下):进阶

    摘要:第一次了解这项特性的时候,真的有一种豁然开朗,发现新大陆的感觉。在绝大多数情况下,是更好的选择。唯一例外的就是需要根据新的来进行操作的场景。会保证在页面渲染前执行,也就是说页面渲染出来的是最终的效果。上面条规则都是为了保证调用顺序的稳定性。 欢迎关注我的公众号睿Talk,获取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、...

    APICloud 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<