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 option删除代码集合
Nov 12 Javascript
用JS判别浏览器种类以及IE版本的几种方法小结
Aug 02 Javascript
js实现省市联动效果的简单实例
Feb 10 Javascript
JavaScript检查弹出窗口是否被阻拦的方法技巧
Mar 13 Javascript
在jQuery中使用$而避免跟其它库产生冲突的方法
Aug 13 Javascript
jQuery使用contains过滤器实现精确匹配方法详解
Feb 25 Javascript
jQuery弹出窗口打开链接的实现代码
Dec 24 Javascript
jquery实现限制textarea输入字数的方法
Sep 06 jQuery
js通过Date对象实现倒计时动画效果
Oct 27 Javascript
基于ES6作用域和解构赋值详解
Nov 03 Javascript
vue中slot(插槽)的介绍与使用
Nov 12 Javascript
详解Anyscript开发指南绕过typescript类型检查
Sep 23 Javascript
详解JVM系列之内存模型
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
一文搞懂redux在react中的初步用法
Jun 09 #Javascript
深入详解JS函数的柯里化
Jun 09 #Javascript
javascript canvas实现雨滴效果
用JS实现飞机大战小游戏
Jun 09 #Javascript
原生JS实现飞机大战小游戏
You might like
PHP中SimpleXML函数用法分析
2014/11/26 PHP
php实现的树形结构数据存取类实例
2014/11/29 PHP
php实现简单的MVC框架实例
2015/09/23 PHP
PHP实现Session入库/存入redis的方法
2017/05/04 PHP
PHP 断点续传实例详解
2017/11/11 PHP
php微信开发之音乐回复功能
2018/06/14 PHP
Laravel 实现关系模型取出需要的字段
2019/10/10 PHP
多种方法实现load加载完成后把图片一次性显示出来
2014/02/19 Javascript
百度移动版的url编码解码示例
2014/04/29 Javascript
jQuery子属性过滤选择器用法分析
2015/02/10 Javascript
js数组常见操作及数组与字符串相互转化实例详解
2015/11/10 Javascript
AngularJS基础 ng-click 指令示例代码
2016/08/01 Javascript
jquery popupDialog 使用 加载jsp页面的方法
2016/10/25 Javascript
JavaScript数据结构之数组的表示方法示例
2017/04/12 Javascript
详解vue.js2.0父组件点击触发子组件方法
2017/05/10 Javascript
Vue中如何实现轮播图的示例代码
2017/07/27 Javascript
Angularjs的$http异步删除数据详解及实例
2017/07/27 Javascript
Cpage.js给组件绑定事件的实现代码
2017/08/31 Javascript
在vue中实现点击选择框阻止弹出层消失的方法
2018/09/15 Javascript
移动端H5页面返回并刷新页面(BFcache)的方法
2018/11/06 Javascript
浅谈vue加载优化策略
2019/03/19 Javascript
浅谈vue项目,访问路径#号的问题
2020/08/14 Javascript
Vue组件通信$attrs、$listeners实现原理解析
2020/09/03 Javascript
js实现简易ATM功能
2020/10/27 Javascript
[01:39](回顾)各路豪强针锋相对,几经鏖战四强产生
2014/07/01 DOTA
[10:49]2014国际邀请赛 叨叨刀塔第二期为真正的电竞喝彩
2014/07/21 DOTA
Python列表推导式的使用方法
2013/11/21 Python
python实现模拟按键,自动翻页看u17漫画
2015/03/17 Python
仅用500行Python代码实现一个英文解析器的教程
2015/04/02 Python
Python logging管理不同级别log打印和存储实例
2018/01/19 Python
Django REST framwork的权限验证实例
2020/04/02 Python
莫斯科的韩国化妆品店:Sifo
2019/12/04 全球购物
师范生自荐信
2013/10/27 职场文书
学校安全生产月活动总结
2014/07/05 职场文书
2014年学校党建工作总结
2014/11/11 职场文书
音乐会主持人开场白
2015/05/28 职场文书