React中的Context应用场景分析


Posted in Javascript onJune 11, 2021

Context定义和目的

Context 提供了一种在组件之间共享数据的方式,而不必显式地通过组件树的逐层传递 props。

应用场景 哪些数据会需要共享?

Context 设计目的是为了共享那些对于一个组件树而言是**“全局”的数据**,例如当前认证的用户、主题或首选语言。

使用步骤

1. 创建并初始化Context

const MyContext = createContex(defaultValue);

创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。

2. 订阅Context

<MyContext.Provider value={/* 某个值 */}>

Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。

这里有两个相关的概念

  • Provider - Context提供者,或Context的订阅者。可以理解为通过Provider为其内部组件订阅了Context值的变动,一旦Context值有变化,就会触发内部组件重新渲染。
  • Comsumer - Context消费者(消费组件),或者叫Context使用者。即在Provider内部使用useContext()来使用或消费Context的组件。这些组件通过useContext()获取、使用Context的最新值。

3. 使用Conext

3.1 React组件中使用

const value = useContext(MyContext);

在消费组件中引用Context。value会从组件树中离自身最近的那个匹配的Provider中读取到当前的Context值。

3.2 纯函数式组件中使用

在纯函数式的组件中,可以使用Consumer来引用context的值。如果没有上层对应的Provider,value等同于传递给createContext()defaultValue.

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

4. Context的更新

4.1 自上而下更新Context

自上而下更新指的是更新Provider的value值。当 Provider 的 value 值发生变化时,它内部的所有消费组件内通过useContext获取到的值会自动更新,并触发重新渲染。

//App.js

// ....

export default function App() {
    //...
    
    // 
    const {contextValue, setContextValue} = React.useState(initialValue);

    // function to update the context value
    function updateContext(newValue) {
        // ...

        // 更新contextValue, ConsumerComponent1, ConsumerComponent2, ConsumerComponent3, ConsumerComponent11都会触发重新渲染。
        setContextValue(newValue)
    }

    ...
    return (
        <App>
            <MyContext.Provider value={contextValue}>
                <ConsumerComponent1>
                    <ConsumerComponent11>
    					// ....
                    </ComsumerComponent11>
                </ConsumerComponent1>

                <ConsumerComponent2 />
                <ConsumerComponent3 />
            </MyContext.Provider>
        </App>
    );
    
}

4.2 自下而上(从消费组件)更新Context

在某些情况下,需要在某个消费组件内更新context,并且适配到整个程序。比如通过应用程序的setting组件修改UI风格。 这时就需要通过回调将更新一层层传递到对应的Provider,更新Provide对应的value,从而触发所有相关消费组件的更新。

// app.js

export default function App() {
    ...
    const {contextValue, setContextValue} = React.useState(initialValue);

    // function to update the context value
    function updateContext(newValue) {
        // ...

        // 更新contextValue, ConsumerComponent1, ConsumerComponent2, ConsumerComponent3, ConsumerComponent11都会触发重新渲染。
        setContextValue(newValue)
    }

    ...
    return (
        <App>
            <MyContext.Provider value={contextValue}>
                <ConsumerComponent1>
                    <ConsumerComponent11 updateValue={updateContext}> // 通过回调形式的props, 在ConsumerComponent11中更新contextValue, 因为contextValue属于最顶层的Provider的值,所以也会触发ConsumerComponent1, ConsumerComponent2, ConsumerComponent3重新渲染。
                    </ComsumerComponent11>
                </ConsumerComponent1>

                <ConsumerComponent2 />
                <ConsumerComponent3 />
            </MyContext.Provider>
        </App>
    );
}

4.3 Provider嵌套

在一些情况下,可能会出现同一个Context的provider嵌套的情况,这时候可以理解为两个Context。不同的是,

...
const {contextValue, setContextValue} = React.useState(initialValue);

// function to update the context value
function updateContext(newValue) {
    // ...
    
    // 更新contextValue, ConsumerComponent1, ConsumerComponent2, ConsumerComponent3, ConsumerComponent11都会触发重新渲染。
    setContextValue(newValue)
}

...
return (
	<App>
        <MyContext.Provider value={contextValue}>
            <ConsumerComponent1>
                <ConsumerComponent11 />
            </ConsumerComponent1>

            <ConsumerComponent2>
                ...
                // 如果只希望更新ComsumerComponent21, ComsumerComponent22中的值
                
                const localContextValue = useContext(MyContext); // 从上一层Provider中获取当前值

				const {tempContextValue, setTempContextValue} = React.useState(localContextValue);

				function updateTempContext(newValue) {
                    // 这里更新以后只会触发ConsumerComponent21和ConsumerComponent22的重新渲染
                    setTempContextValue(newValue); 
                }

				// 这里新建Provider,在ConsumerComponent21和ConsumerComponent22之间共享数据。
                <MyContext.Provider value={tempValue}>
                    <ConsumerComponent21>
                    	// 在ConsumerComponent21中通过useContext(MyContext)订阅
                    	// 获取到的值为离自身最近的那个匹配的Provider中读取到的Context值,即tempValue
                    </ConsumerComponent21>
                    <ConsumerComponent22>
                    </ConsumerComponent22>
				</MyContext.Provider value={contextValue}>
            </ConsumerComponent2>
            <ConsumerComponent3 />
        </MyContext.Provider>
    </App>
);

官方文档

官方文档请参考下边的基础和高级教程。

Hook API 索引 ? React (reactjs.org)

Context ? React (reactjs.org)

以上就是React中的Context应用场景分析的详细内容,更多关于React中的Context的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JS对URL字符串进行编码/解码分析
Oct 25 Javascript
url 特殊字符 传递参数解决方法
Jan 01 Javascript
javascript模拟实现C# String.format函数功能代码
Nov 25 Javascript
基于JS实现Android,iOS一个手势动画效果
Apr 27 Javascript
Javascript类型系统之undefined和null浅析
Jul 13 Javascript
如何理解jQuery中的ajaxSubmit方法
Mar 13 Javascript
Vuex 入门教程
Jan 10 Javascript
Vue中的methods、watch、computed的区别
Nov 26 Javascript
vuejs简单验证码功能完整示例
Jan 08 Javascript
用Cordova打包Vue项目的方法步骤
Feb 02 Javascript
vue请求本地自己编写的json文件的方法
Apr 25 Javascript
JavaScript对象原型链原理解析
Jan 22 Javascript
详解JVM系列之内存模型
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
一文搞懂redux在react中的初步用法
Jun 09 #Javascript
深入详解JS函数的柯里化
Jun 09 #Javascript
javascript canvas实现雨滴效果
用JS实现飞机大战小游戏
Jun 09 #Javascript
原生JS实现飞机大战小游戏
You might like
Re:从零开始的异世界生活 第2季 开播啦
2020/07/24 日漫
如何修改和添加Apache的默认站点目录
2013/07/05 PHP
PHP实现合并discuz用户
2015/08/05 PHP
图文详解PHP环境搭建教程
2016/07/16 PHP
javascript学习笔记(二十) 获得和设置元素的特性(属性)
2012/06/20 Javascript
JavaScript 反科里化 this [译]
2012/09/20 Javascript
原生JS可拖动弹窗效果实例代码
2013/11/09 Javascript
当达到输入长度时表单自动切换焦点
2014/04/06 Javascript
JS和JQ的event对象区别分析
2014/11/24 Javascript
javascript判断数组内是否重复的方法
2015/04/21 Javascript
jQuery soColorPacker 网页拾色器
2016/06/22 Javascript
jQuery Easyui快速入门教程
2016/08/21 Javascript
浅谈jQuery中Ajax事件beforesend及各参数含义
2016/12/03 Javascript
详解nodejs微信公众号开发——4.自动回复各种消息
2017/04/11 NodeJs
Node.js v8.0.0正式发布!看看带来了哪些主要新特性
2017/06/02 Javascript
谈谈VUE种methods watch和compute的区别和联系
2017/08/01 Javascript
EL表达式截取字符串的函数说明
2017/09/22 Javascript
Angular2开发环境搭建教程之VS Code
2017/12/15 Javascript
Vue中axios拦截器如何单独配置token
2019/12/27 Javascript
JavaScript常用进制转换及位运算实例解析
2020/10/14 Javascript
[02:19]DOTA2上海特级锦标赛 观赛指南 Spectator Guide
2016/02/04 DOTA
浅析Python中的getattr(),setattr(),delattr(),hasattr()
2016/06/14 Python
深入解析Python的Tornado框架中内置的模板引擎
2016/07/11 Python
详解python中@的用法
2019/03/27 Python
如何使用pyinstaller打包32位的exe程序
2019/05/26 Python
基于django传递数据到后端的例子
2019/08/16 Python
python控制台实现tab补全和清屏的例子
2019/08/20 Python
python对指定字符串逆序的6种方法(小结)
2020/04/02 Python
Python 如何查找特定类型文件
2020/08/17 Python
WatchShop法国:英国排名第一的独立手表零售商
2020/02/17 全球购物
新西兰购物网站:TheMarket NZ
2020/09/19 全球购物
意外伤害赔偿协议书范文
2014/09/23 职场文书
2015年预防青少年违法犯罪工作总结
2015/05/22 职场文书
色戒观后感
2015/06/12 职场文书
新学期主题班会
2015/08/17 职场文书
Redis 常见使用场景
2021/08/30 Redis