一.产生context原因

从父组件直接传值到孙子组件,而不必一层一层的通过props进行传值,相比较以前的那种传值更加的方便、简介。

二.context的两种实现方式

1.老版本(React16.x前)

//根组件
class MessageList extends React.Component {
//getChildContext函数,返回一个context对象
getChildContext() {
return { color: 'purple', text: 'item text' }
}
render() {
return (
<div>
<Message text="this is MessageList" />
</div>
)
}
}
//指定context结构类型 如果不写 产生错误
//import T from 'prop-types';
MessageList.childContextTypes = {
color: T.string,
text: T.string,
}
//中间组件
class Message extends React.Component {
render() {
return (
<div>
<MessageItem />
</div>
)
}
}
//孙子组件(接收组件)
class MessageItem extends React.Component {
render() {
//this.context获取上下文
return (
<div>
{this.context.text}
</div>
)
}
}
//孙子组件声明 接收context结构类型 如果contextTypes没有定义 context将是一个空对象
MessageItem.contextTypes = {
text: T.string
}

为什么会被摒弃?

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

2.新版本(React16.x后)

//创建两个组件 Provider,Consumer
//let {Provider,Consumer}=React.createContext(defaultValue); //defaultValue可以设置共享的默认数据 当Provider不存在的时候 defaultValue生效
const { Provider, Consumer } = React.createContext({ theme: "green" }) // 这里MessageList render(){<Content />}
class MessageList extends React.Component {
render() {
//Procider组件遍历子组件,并且有一个属性value,且value相当于旧版本的getChildContext()的返回的context对象 用来提供数据
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的一个变化
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 = {
//context的$$typeof在createElement中的type对象中存储的
$$typeof: REACT_CONTEXT_TYPE,
//作为支持多个并发渲染器的解决方法 我们将一些渲染器作为主要渲染器 其他渲染器为辅助渲染器
_calculateChangedBits: calculateChangedBits,
//我们希望有两个并发渲染器:主要和次要
//辅助渲染器将自己的context的value存储在单独的字段里
//_currentValue和_currentValue2作用一样,只是作用平台不同
_currentValue: defaultValue, //Provider的value属性
_currentValue2: defaultValue,
//用来追踪context的并发渲染器的数量
_threadCount: 0,
// 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
}; // $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;
}

返回的context内容:

React的React.createContext()源码解析(四)的更多相关文章

  1. Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?

    Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的?   如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...

  2. Sentinel源码解析四(流控策略和流控效果)

    引言 在分析Sentinel的上一篇文章中,我们知道了它是基于滑动窗口做的流量统计,那么在当我们能够根据流量统计算法拿到流量的实时数据后,下一步要做的事情自然就是基于这些数据做流控.在介绍Sentin ...

  3. React的Component,PureComponent源码解析(二)

    1.什么是Component,PureComponent? 都是class方式定义的基类,两者没有什么大的区别,只是PureComponent内部使用shouldComponentUpdate(nex ...

  4. Dubbo 源码解析四 —— 负载均衡LoadBalance

    欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 Dubbo 入门之二 --- 项目结构解析 Dubbo 源码分析系列之三 -- 架构原 ...

  5. iOS即时通讯之CocoaAsyncSocket源码解析四

    原文 前言: 本文为CocoaAsyncSocket源码系列中第二篇:Read篇,将重点涉及该框架是如何利用缓冲区对数据进行读取.以及各种情况下的数据包处理,其中还包括普通的.和基于TLS的不同读取操 ...

  6. AFNetworking2.0源码解析<四>

    结构 AFURLResponseSerialization负责解析网络返回数据,检查数据是否合法,把NSData数据转成相应的对象,内置的转换器有json,xml,plist,image,用户可以很方 ...

  7. Celery 源码解析四: 定时任务的实现

    在系列中的第二篇我们已经看过了 Celery 中的执行引擎是如何执行任务的,并且在第三篇中也介绍了任务的对象,但是,目前我们看到的都是被动的任务执行,也就是说目前执行的任务都是第三方调用发送过来的.可 ...

  8. vuex 源码解析(四) mutation 详解

    mutation是更改Vuex的store中的状态的唯一方法,mutation类似于事件注册,每个mutation都可以带两个参数,如下: state ;当前命名空间对应的state payload ...

  9. MyBatis 3源码解析(四)

    四.MyBatis 查询实现 Employee empById = mapper.getEmpById(1); 首先会调用MapperProxy的invoke方法 @Override public O ...

随机推荐

  1. C语言合并两个有序链表

    将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4输出:1->1->2-& ...

  2. JS高级---递归

    递归 递归: 函数中调用函数自己, 此时就是递归, 递归一定要有结束的条件   var i = 0; function f1() { i++; if (i < 5) { f1(); } cons ...

  3. [CodeIgniter4]故障排除和本地开发服务器

    故障排除 以下是一些常见的安装问题,以及建议的解决方法. 我必须在我的URL中包含index.php 如果``/mypage/find/apple``类似的URL``/index.php/mypage ...

  4. Ubuntu切换默认sh为bash或者dash

    Ubuntu切换默认sh为bash或者dash   1 bash与dash 从Ubuntu 6.10开始,默认使用dash(theDebian Almquist Shell)而不是bash(the G ...

  5. linux命令 mv

    后缀--backup=<备份模式>:若需覆盖文件,则覆盖前先行备份: -b:当文件存在时,覆盖前,为其创建一个备份: -f:若目标文件或目录与现有的文件或目录重复,则直接覆盖现有的文件或目 ...

  6. Chrome浏览器所有页面崩溃

    问题描述 Chrome浏览器所有页面崩溃,包括设置页面,"喔唷,崩溃啦!" 显示错误码:STATUS_INVALID_IMAGE_HASH Chrome所有插件报错,右下角一串弹框 ...

  7. 算法导论2-4 O(nlgn)时间复杂度求逆序对

    def mergesort(nums,le,ri): if le>ri-2: return 0 mi=le+(ri-le)//2 a=mergesort(nums,le,mi) b=merges ...

  8. 四种常见的APP分类界面布局设计案例学习

    相信各位对于APP设计,已经很熟练啦.如何在熟练的基础上提高我们界面的优美度,或者是进行APP界面的迭代设计. 重构APP设计布局是我们必须要经历的一个过程. 在之前,学习UI设计的时候,经常要接触到 ...

  9. 初识Vue--生命周期

    初学Vue,写一些随记谨防忘记,不足之处谢谢指出!!! 本文可以直接复制自行创建一个HTML页面,查看结果. <!DOCTYPE html> <html lang="en& ...

  10. 给html元素添加自定义属性,并且用jquery进行筛选

    例如有多个div,想要实现类似radio的效果. <div name="teacher" selected="selected">tch1</ ...