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 相关文章推荐
一直复略了的一个问题,关于表单重复提交
Feb 15 Javascript
JQuery 入门实例1
Jun 25 Javascript
JavaScript CSS修改学习第五章 给“上传”添加样式
Feb 19 Javascript
javascript之学会吝啬 精简代码
Apr 25 Javascript
jQuery选择器简明总结(含用法实例,一目了然)
Apr 25 Javascript
CSS3,HTML5和jQuery搜索框集锦
Dec 02 Javascript
jQuery实现新消息闪烁标题提示的方法
Mar 11 Javascript
JS清除文本框内容离开在恢复及鼠标离开文本框时触发js的方法
Jan 12 Javascript
jQuery实现对无序列表的排序功能(附demo源码下载)
Jun 25 Javascript
使用JavaScript判断手机浏览器是横屏还是竖屏问题
Aug 02 Javascript
bootstrap制作jsp页面(根据值让table显示选中)
Jan 05 Javascript
解决vue单页面应用中动态修改title问题
Jun 09 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使用内置函数生成图片的方法详解
2016/05/09 PHP
PDO实现学生管理系统
2020/03/21 PHP
基于jQuery的星级评分插件
2011/08/12 Javascript
Node.js实战 建立简单的Web服务器
2012/03/08 Javascript
js split 的用法和定义 js split分割字符串成数组的实例代码
2012/05/13 Javascript
JSONP 跨域共享信息
2012/08/16 Javascript
玩转NODE.JS(四)-搭建简单的聊天室的代码
2016/11/11 Javascript
jQuery编写网页版2048小游戏
2017/01/06 Javascript
js仿拉勾网首页穿墙广告效果
2017/03/08 Javascript
微信小程序开发之toast提示插件使用示例
2017/06/08 Javascript
jQuery回调方法使用示例
2017/06/26 jQuery
基于angular6.0实现的一个组件懒加载功能示例
2018/04/12 Javascript
JavaScript使用prototype原型实现的封装继承多态示例
2018/08/31 Javascript
Vue循环组件加validate多表单验证的实例
2018/09/18 Javascript
jQuery easyui datagird编辑行删除行功能的实现代码
2018/09/20 jQuery
Django+vue跨域问题解决的详细步骤
2019/01/20 Javascript
详解JavaScript作用域和作用域链
2019/03/19 Javascript
AntV F2和vue-cli构建移动端可视化视图过程详解
2019/10/08 Javascript
Vue项目中使用jsonp抓取跨域数据的方法
2019/11/10 Javascript
js canvas实现俄罗斯方块
2020/10/11 Javascript
[44:33]EG vs Liquid 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python绘制漏斗图步骤详解
2019/03/04 Python
python f-string式格式化听语音流程讲解
2019/06/18 Python
python实现美团订单推送到测试环境,提供便利操作示例
2019/08/09 Python
python如何修改文件时间属性
2021/02/05 Python
Trip.com香港网站:Ctrip携程旗下,全球最大的网上旅游社之一
2016/08/01 全球购物
精美的手工家居和生活用品:Nkuku
2019/11/01 全球购物
在使用非全零作为空指针内部表达的机器上, NULL是如何定义
2014/11/09 面试题
小区门卫管理制度
2014/01/29 职场文书
社区志愿者活动总结
2014/06/26 职场文书
毕业生就业推荐表导师评语
2014/12/31 职场文书
2015年银行柜员工作总结报告
2015/04/01 职场文书
给朋友的道歉短信
2015/05/12 职场文书
2016年小学生清明节广播稿
2015/12/17 职场文书
CSS3 实现的图片悬停的切换按钮
2021/04/13 HTML / CSS
Python爬虫实战之爬取携程评论
2021/06/02 Python