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 相关文章推荐
深入理解JavaScript系列(29):设计模式之装饰者模式详解
Mar 03 Javascript
JS导出PDF插件的方法(支持中文、图片使用路径)
Jul 12 Javascript
JavaScript基于对象去除数组重复项的方法
Oct 09 Javascript
JavaScript队列、优先队列与循环队列
Nov 14 Javascript
vue修改vue项目运行端口号的方法
Aug 04 Javascript
详解jQuery同步Ajax带来的UI线程阻塞问题及解决办法
Aug 09 jQuery
javascript用rem来做响应式开发
Jan 13 Javascript
微信小程序实现上传图片功能
May 28 Javascript
vue内置组件transition简单原理图文详解(小结)
Jul 12 Javascript
JS实现数组去重,显示重复元素及个数的方法示例
Jan 21 Javascript
uniapp实现可滑动选项卡
Oct 21 Javascript
Vue.js中v-for指令的用法介绍
Mar 13 Vue.js
详解JVM系列之内存模型
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
一文搞懂redux在react中的初步用法
Jun 09 #Javascript
深入详解JS函数的柯里化
Jun 09 #Javascript
javascript canvas实现雨滴效果
用JS实现飞机大战小游戏
Jun 09 #Javascript
原生JS实现飞机大战小游戏
You might like
PHP写MySQL数据 实现代码
2009/06/15 PHP
php中autoload的用法总结
2013/11/08 PHP
php中实现精确设置session过期时间的方法
2014/07/17 PHP
PHP调用wsdl文件类型的接口代码分享
2014/11/19 PHP
php上传文件并存储到mysql数据库的方法
2015/03/16 PHP
为你总结一些php信息函数
2015/10/21 PHP
微信公众平台DEMO(PHP)
2016/05/04 PHP
javascript编程起步(第六课)
2007/02/27 Javascript
对google个性主页的拖拽效果的js的完整注释[转]
2007/04/10 Javascript
基于jquery的让页面控件不可用的实现代码
2010/04/27 Javascript
最佳的addEvent事件绑定是怎样诞生的
2011/10/24 Javascript
js+html+css实现鼠标移动div实例
2013/01/30 Javascript
解析js如何获取当前url中的参数值并复制给input
2013/06/23 Javascript
js动态创建及移除div的方法
2015/06/03 Javascript
jquery彩色投票进度条简单实例演示
2020/07/23 Javascript
js实现页面跳转的五种方法推荐
2016/03/10 Javascript
不同js异步函数同步的实现方法
2016/05/28 Javascript
KnockoutJS 3.X API 第四章之表单textInput、hasFocus、checked绑定
2016/10/11 Javascript
Bootstrap导航中表单简单实现代码
2017/03/06 Javascript
详解vue axios二次封装
2018/07/22 Javascript
深入理解Python 关于supper 的 用法和原理
2018/02/28 Python
Python实现微信小程序支付功能
2019/07/25 Python
使用OpenCV对车道进行实时检测的实现示例代码
2020/06/19 Python
python 实现批量图片识别并翻译
2020/11/02 Python
html5 css3网站菜单实现代码
2013/12/23 HTML / CSS
html5 datalist 选中option选项后的触发事件
2020/03/05 HTML / CSS
白宫黑市官网:White House Black Market
2016/11/17 全球购物
外包公司软件测试工程师
2014/11/01 面试题
学校募捐倡议书
2014/05/14 职场文书
设立有限责任公司出资协议书
2014/11/01 职场文书
奖学金个人总结
2015/03/04 职场文书
穆斯林的葬礼读书笔记
2015/06/26 职场文书
cf战队宣传语
2015/07/13 职场文书
mysql获取指定时间段中所有日期或月份的语句(不设存储过程,不加表)
2021/06/18 MySQL
SpringBoot快速入门详解
2021/07/21 Java/Android
Java8利用Stream对列表进行去除重复的方法详解
2022/04/14 Java/Android