写在前面

​ 鉴于笔者学习此内容章节 React官方文档 时感到阅读理解抽象困难,所以决定根据文档理解写一篇自己对Context的理解,文章附带示例,以为更易于理解学习。更多内容请参考 React官方文档

​ 如果您觉得文章对您有帮助,可以点击文章右下角【[推荐](javascript:void(0)】一下。您的鼓励是笔者创作的最大动力!

​ 如果发现文章有问题也可以在文章下方及时联系笔者哦,相互探讨一起进步~

基本概念

  • ContextReact中为了避免在不同层级组件中逐层传递props的产物,在没有Context的时候父组件向子组件传递props属性只能在组件树上自上而下进行传递,但是有些属性并不是组件树的每层节点都有相同的需求,这样我们再这样逐层传递props就显得代码很繁琐笨重。
  • 使用React.createContext(defulData)可以通过创建一个ContextObject,在某个组件中调用ContextObject.Provider同时可以设置新的value = newData覆盖掉defulData共享到下面的所有子组件,需要ContextObject共享出来的数据的子组件可以通过static contextType = ContextObject接收到data,使用this.context即可调用data

适用场景

  • 很多不同层级的组件需要访问同样的数据,所以如果我们只是想避免层层传递一些属性,那么我们还有更好的选择: 组合组件

Context API 理解与运用

  • React.createContext(defaultValue)

    创建一个Context对象,defaultValue是默认参数,在一个组件中可以调用这个对象的ProviderAPI,并且设置新的参数:
const Context = React.createContext(defaultValue)
function ContextProvider () {
return (
<Context.Provider value = { newValue }>
/* 子组件(这里的组件及其子组件都可以收到这个Context对象发出的newValue) */
<Context.Provider/>
)
}

​ 但是如果没有对应的Context.Provider相匹配,那么组件树上的所有组件都可以收到这个Context对象发出 的defaultValue

​ 同时可以调用ContextConsumerAPI可以用来接受到Context的值,并且根据这个值渲染组件:

function ContextConsumer () {
return (
<Context.Comsumer>
{value =>
<div>
/* 可以根据value进行渲染 */
</div>
}
</Context.Comsumer>
)
}
  • Context.Provider & Context.Comsumer

    • <MyContext.Provider value={ variableValue }>可以允许消费组件订阅到variableValue 值的变化,也就是说消费组件可以根据variableValue值的变化而变化,variableValue的值我们可以定义一个事件来控制改变;

    <MyContext.Consumer>
    {value => /* 基于 context 值进行渲染*/}
    </MyContext.Consumer>

    利用Context.Consumer API 可以让我们即使是在函数式组件也可以订阅到 Context的值;

    这种方法需要一个函数作为子元素,函数接收当前的context值,并返回一个 React 节点。

    传递给函数的 value 值等价于组件树上方离这个 context 最近的 Provider 提供的 variableValue 值。如果没有对应的 Provider,value 参数等同于传递给 createContext()defaultValue

    // Provider 结合 Consumer 使用示例
    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    // 创建 Context 对象
    const MyContext = React.createContext(0) // defaultValue 是数字0 // App组件 渲染 Context 对象
    class App extends React.Component {
    constructor(props){
    super(props);
    this.state = {
    variableValue : 0
    }
    // 处理 Provider中value变化的函数
    this.handleChange = () => {
    this.setState(state => ({
    variableValue: state.variableValue + 1
    })
    )
    }
    }
    render(){
    return (
    // 调用 Context.Provider, 设置可以让Consumer组件监听变化的 value 值
    <MyContext.Provider value = {this.state.variableValue}>
    <Context changeValue = {this.handleChange}/>
    </MyContext.Provider>
    )
    }
    }
    // 消费组件
    class Context extends React.Component{
    render(){
    return (
    <MyContext.Consumer>
    /* 根据Context的value进行渲染 */
    {value =>
    <button onClick={this.props.changeValue} >
    Add MyValue:{value}
    </button>
    }
    </MyContext.Consumer>
    )
    }
    }
    ReactDOM.render(
    <App className = 'app'/>
    ,
    document.getElementById('root')
    );

    当Provider的 variableValue值发生变化时,它内部的所有消费组件都会重新渲染。

  • Class.contextType

    class MyClass extends React.Component {
    render() {
    let value = this.context; // this.context 可以访问到 MyClass 的contextType
    /* 基于 MyContext 组件的值进行渲染 */
    }
    }
    MyClass.contextType = MyContext; //将MyClass的contextType属性赋值为 Context 对象的值

    挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象。此属性能让你使用 this.context 来消费最近 Context 上的那个值。你可以在任何生命周期中访问到它,包括 render 函数中。

    注: 从文档的字面意思,Class.contextType类组件特有的API,所以函数式组件只能使用 Context.Consumer来访问 Context对象的值,我们可以来试一下类组件和函数式组件的API:

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    // 创建 Context 对象
    const MyContext = React.createContext(0)
    // App组件 渲染 Context 对象
    class App extends React.Component {
    constructor(props){
    super(props);
    this.state = {
    variableValue : 0
    }
    this.handleChange = () => {
    this.setState(state => ({
    variableValue: state.variableValue + 1
    })
    )
    }
    }
    render(){
    return (
    // 调用 Context.Provider, 设置可以让Consumer组件监听变化的 value 值
    <MyContext.Provider value = {this.state.variableValue}>
    <Context_consumer changeValue = {this.handleChange} />
    <br/>
    <Context_contextType changeValue = {this.handleChange} />
    <br />
    <Func_Consumer changeValue = {this.handleChange} />
    <br />
    <func_contextType changeValue = {this.handleChange} />
    </MyContext.Provider>
    )
    }
    }
    // Class & Consumer 消费组件
    class Context_consumer extends React.Component{
    render(){
    return (
    <MyContext.Consumer>
    {value =>
    <button onClick={this.props.changeValue} >
    Add Class_consumer:{value}
    </button>
    }
    </MyContext.Consumer>
    )
    }
    }
    // Class & contextType 的消费组件
    class Context_contextType extends React.Component{
    render(){
    let value = this.context
    return (
    <button onClick={this.props.changeValue} >
    Add Class_contextType:{value}
    </button>
    )
    }
    };
    Context_contextType.contextType = MyContext;
    // 函数组件 & Consumer
    function Func_Consumer (props) {
    return (
    <MyContext.Consumer>
    {value =>
    <button onClick={props.changeValue} >
    Add Func_consumer:{value}
    </button>
    }
    </MyContext.Consumer>
    )
    } // 函数组件 & contextType
    function func_contextType (props) {
    let value = this.context
    return (
    <button onClick={props.changeValue} >
    Add func_contextType:{value}
    </button>
    )
    }
    func_contextType.contextType = MyContext; ReactDOM.render(
    <App className = 'app'/>
    ,
    document.getElementById('root')
    );

    运行结果:

    除了func_contextType组件之外其他组件都可以正常运行

    avatar

  • Context.displayName

    context 对象接受一个名为 displayName 的 property,类型为字符串。React DevTools 使用该字符串来确定 context 要显示的内容。

    示例,下述组件在 DevTools 中将显示为 MyDisplayName:

    const MyContext = React.createContext(/* some value */);
    MyContext.displayName = 'MyDisplayName';
    <MyContext.Provider> // "MyDisplayName.Provider" 在 DevTools 中
    <MyContext.Consumer> // "MyDisplayName.Consumer" 在 DevTools 中

React Context 理解和使用的更多相关文章

  1. 探索 Redux4.0 版本迭代 论基础谈展望(对比 React context)

    Redux 在几天前(2018.04.18)发布了新版本,6 commits 被合入 master.从诞生起,到如今 4.0 版本,Redux 保持了使用层面的平滑过渡.同时前不久, React 也从 ...

  2. context理解

    官方文档的解释是:Context提供了关于应用环境全局信息的接口.它是一个抽象类,它的执行被Android系统所提供.它允许获取以应用为特征的资源和类型.同时启动应用级的操作,如启动Activity, ...

  3. React context基本用法

    React的context就是一个全局变量,可以从根组件跨级别在React的组件中传递.React context的API有两个版本,React16.x之前的是老版本的context,之后的是新版本的 ...

  4. [React] Prevent Unnecessary Rerenders of Compound Components using React Context

    Due to the way that React Context Providers work, our current implementation re-renders all our comp ...

  5. React Context API

    使用React 开发程序的时候,组件中的数据共享是通过数据提升,变成父组件中的属性,然后再把属性向下传递给子组件来实现的.但当程序越来越复杂,需要共享的数据也越来越多,最后可能就把共享数据直接提升到最 ...

  6. React Hooks +React Context vs Redux

    React Hooks +React Context vs Redux https://blog.logrocket.com/use-hooks-and-context-not-react-and-r ...

  7. 对 React Context 的理解以及应用

    在React的官方文档中,Context被归类为高级部分(Advanced),属于React的高级API,但官方并不建议在稳定版的App中使用Context. 很多优秀的React组件都通过Conte ...

  8. [译]React Context

    欢迎各位指导与讨论 : ) 前言 由于笔者英语和技术水平有限,有不足的地方恳请各位指出.我会及时修正的 O(∩_∩)O 当前React版本 15.0.1 时间 2016/4/25 正文 React一个 ...

  9. 对React的理解

    转自:http://www.cocoachina.com/webapp/20150721/12692.html 现在最热门的前端框架有AngularJS.React.Bootstrap等.自从接触了R ...

随机推荐

  1. CCF-最优配餐(BFS)

    最优配餐   问题描述 栋栋最近开了一家餐饮连锁店,提供外卖服务.随着连锁店越来越多,怎么合理的给客户送餐成为了一个急需解决的问题.栋栋的连锁店所在的区域可以看成是一个n×n的方格图(如下图所示),方 ...

  2. IntelliJ IDEA 内置数据库管理工具实战

    1. 写在前面 开发Java应用程序,作为明星工具IntelliJ IDEA Ultimate当然是首选,然后进行数据库SQL开发的时候,常常会选择诸如:Navicat , sqlyog, MySQL ...

  3. python爬虫selenium相关

    首先上很好用的selenium中文文档,基本上所有问题都能通过阅读此文档解决.可惜好像没找到翻译者名称. https://python-selenium-zh.readthedocs.io/zh_CN ...

  4. Codeforces Global Round 9 C. Element Extermination

    题目链接:https://codeforces.com/contest/1375/problem/C 题意 给出一个大小为 $n$ 的排列 $a$,如果 $a_i < a_{i+1}$,则可以选 ...

  5. 2020牛客暑期多校训练营(第二场)Fake Maxpooling

    传送门:Fake Maxpooling 题意:给出矩阵的行数n和列数m,矩阵 Aij = lcm( i , j )  ,求每个大小为k*k的子矩阵的最大值的和. 题解:如果暴力求解肯定会t,所以要智取 ...

  6. Codeforces Round #647 (Div. 2) C. Johnny and Another Rating Drop(数学)

    题目链接:https://codeforces.com/contest/1362/problem/C 题意 计算从 $0$ 到 $n$ 相邻的数二进制下共有多少位不同,考虑二进制下的前导 $0$ .( ...

  7. hdu 1045 Fire Net 二分图匹配 && HDU-1281-棋盘游戏

    题意:任意两个个'车'不能出现在同一行或同一列,当然如果他们中间有墙的话那就没有什么事,问最多能放多少个'车' 代码+注释: 1 //二分图最大匹配问题 2 //难点在建图方面,如果这个图里面一道墙也 ...

  8. rabbitmq学习二

    rabbitmq的六种工作模式: 这里简单介绍下六种工作模式的主要特点: 简单模式:一个生产者,一个消费者 work模式:一个生产者,多个消费者,每个消费者获取到的消息唯一. 订阅模式:一个生产者发送 ...

  9. 国产网络损伤仪SandStorm -- 为什么数据流还是走Bypass链路?

    如果你在使用网络损伤仪SandStorm测试移动互联网的应用程序或者在仿真所谓"弱网测试"的时候,发现所有的数据流还是在走Bypass链路,并没有预期地走自己创建的仿真链路,那么你 ...

  10. transformers---FloatProgress not found. Please update jupyter and ipywidgets.

    问题 运行 huggingface transformers 的 demo,报错FloatProgress not found.具体如下: import torch from transformers ...