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创建一个input数组并绑定click事件的方法
Jun 12 Javascript
一款基jquery超炫的动画导航菜单可响应单击事件
Nov 02 Javascript
浅谈JSON中stringify 函数、toJosn函数和parse函数
Jan 26 Javascript
jQuery实现切换字体大小的方法
Mar 10 Javascript
jQuery基于ajax实现星星评论代码
Aug 07 Javascript
完美解决IE不支持Data.parse()的问题
Nov 24 Javascript
jQuery Easy UI中根据第一个下拉框选中的值设置第二个下拉框是否可以编辑
Nov 29 Javascript
js querySelector() 使用方法
Dec 21 Javascript
JS中实现函数return多个返回值的实例
Feb 21 Javascript
JavaScript中的this陷阱的最全收集并整理(没有之一)
Feb 21 Javascript
vue router下的html5 history在iis服务器上的设置方法
Oct 18 Javascript
vue mint-ui tabbar变组件使用
May 04 Javascript
详解JVM系列之内存模型
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
一文搞懂redux在react中的初步用法
Jun 09 #Javascript
深入详解JS函数的柯里化
Jun 09 #Javascript
javascript canvas实现雨滴效果
用JS实现飞机大战小游戏
Jun 09 #Javascript
原生JS实现飞机大战小游戏
You might like
德生PL990,目前市面上唯一一款便携式插卡蓝牙全波段高性能收音机
2021/03/02 无线电
PHP static局部静态变量和全局静态变量总结
2014/03/02 PHP
教你如何用php实现LOL数据远程获取
2014/06/10 PHP
flexigrid 类似ext grid的JS表格代码
2010/07/17 Javascript
扩展JS Date对象时间格式化功能的小例子
2013/12/02 Javascript
javascript 事件处理示例分享
2014/12/31 Javascript
jQuery实现的感应鼠标悬停图片色彩渐显效果
2015/03/03 Javascript
理解Javascript的动态语言特性
2015/06/17 Javascript
node.js express安装及示例网站搭建方法(分享)
2016/08/22 Javascript
html判断当前页面是否在iframe中的实例
2016/11/30 Javascript
基于jPlayer三分屏的制作方法
2016/12/21 Javascript
Vue Spa切换页面时更改标题的实例代码
2017/07/15 Javascript
基于JavaScript实现无限加载瀑布流
2017/07/21 Javascript
jQuery实现checkbox即点即改批量删除及中间遇到的坑
2017/11/11 jQuery
解决layui 表单元素radio不显示渲染的问题
2019/09/04 Javascript
JS中的继承操作实例总结
2020/06/06 Javascript
JavaScript实现京东快递单号查询
2020/11/30 Javascript
[01:24:51]2014 DOTA2华西杯精英邀请赛 5 25 LGD VS NewBee第二场
2014/05/26 DOTA
[53:18]Spirit vs Liquid Supermajor小组赛A组 BO3 第三场 6.2
2018/06/03 DOTA
[01:14:55]EG vs Spirit Supermajor 败者组 BO3 第三场 6.4
2018/06/05 DOTA
Python中import导入上一级目录模块及循环import问题的解决
2016/06/04 Python
Python实现中文数字转换为阿拉伯数字的方法示例
2017/05/26 Python
pycharm打开命令行或Terminal的方法
2019/01/16 Python
python3.7 sys模块的具体使用
2019/07/22 Python
使用pandas读取文件的实现
2019/07/31 Python
python3 配置logging日志类的操作
2020/04/08 Python
html5视频常用API接口的实战示例
2020/03/20 HTML / CSS
台湾全方位线上课程与职能学习平台:TibaMe
2019/12/04 全球购物
MySQL面试题目集锦
2016/04/14 面试题
爱国演讲稿500字
2014/05/04 职场文书
党的群众路线教育实践活动个人对照检查材料(教师)
2014/11/04 职场文书
学校党风廉政建设调研报告
2015/01/01 职场文书
玄武湖导游词
2015/02/05 职场文书
预备党员党支部意见
2015/06/02 职场文书
2015年秋季学校开学标语
2015/07/16 职场文书
在 Python 中利用 Pool 进行多线程
2022/04/24 Python