React中的Context应用场景分析

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的资料请关注我们其它相关文章!

(0)

相关推荐

  • 聊一聊我对 React Context 的理解以及应用

    前言 Context被翻译为上下文,在编程领域,这是一个经常会接触到的概念,React中也有. 在React的官方文档中,Context被归类为高级部分(Advanced),属于React的高级API,但官方并不建议在稳定版的App中使用Context. The vast majority of applications do not need to use content. If you want your application to be stable, don't use context

  • 使用react context 实现vue插槽slot功能

    首先来看下vue的slot的实现 <base-layout>组件,具名插槽name定义以及默认插槽 <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot n

  • React中的Context应用场景分析

    Context定义和目的 Context 提供了一种在组件之间共享数据的方式,而不必显式地通过组件树的逐层传递 props. 应用场景 哪些数据会需要共享? Context 设计目的是为了共享那些对于一个组件树而言是**"全局"的数据**,例如当前认证的用户.主题或首选语言. 使用步骤 1. 创建并初始化Context const MyContext = createContex(defaultValue); 创建一个 Context 对象.当 React 渲染一个订阅了这个 Cont

  • golang 中的 nil的场景分析

    源码中的 nil 是这样定义的 // nil is a predeclared identifier representing the zero value for a // pointer, channel, func, interface, map, or slice type. var nil Type // Type must be a pointer, channel, func, interface, map, or slice type 所以 nil 可以理解为这些类型的零值,声明

  • React中setState同步异步场景的使用

    目录 setState同步异步场景 描述 原理 保证内部数据统一 启用并发更新 参考 setState同步异步场景 React通过this.state来访问state,通过this.setState()方法来更新state,当this.setState()方法被调用的时候,React会重新调用render方法来重新渲染UI.相比较于在使用Hooks完成组件下所需要的心智负担,setState就是在使用class完成组件下所需要的心智负担,当然所谓的心智负担也许叫做所必须的基础知识更加合适一些.

  • React中useLayoutEffect钩子使用场景详解

    目录 简介 useEffect钩子的概述 钩子流程 useLayoutEffect钩子的概述 钩子流程 什么时候使用useLayoutEffect钩子? 总结 简介 不久前,React对其功能组件进行了一次重大更新(在2019年3月的16.8版本中),终于为这些组件提供了一种变得有状态的方法. 钩子的加入不仅意味着功能组件将能够提供自己的状态,而且还能通过引入useEffect钩子来管理自己的生命周期事件. 此外,这次更新还引入了一个全新的useLayoutEffect钩子,根据React文档,

  • react中关于Context/Provider/Consumer传参的使用

    目录 Context/Provider/Consumer传参使用 Context 使用context向后代组件传参 Context/Provider/Consumer传参使用 react context这个api很少用到,所以一直不太清楚如何使用,最近在看antd的项目源码时,发现在组件中有类似Template.Comsumer的写法,一时没反应过来,本着碰到不懂得都要追根究底的原则,下面好好学习一下,Context这个api的使用 Context 作用 上下文(Context) 提供了一种通过

  • 利用consul在spring boot中实现分布式锁场景分析

    因为在项目实际过程中所采用的是微服务架构,考虑到承载量基本每个相同业务的服务都是多节点部署,所以针对某些资源的访问就不得不用到用到分布式锁了. 这里列举一个最简单的场景,假如有一个智能售货机,由于机器本身的原因不能同一台机器不能同时出两个商品,这就要求在在出货流程前针对同一台机器在同一时刻出现并发 创建订单时只能有一笔订单创建成功,但是订单服务是多节点部署的,所以就不得不用到分布式锁了. 以上只是一种简单的业务场景,在各种大型互联网实际应用中,需要分布式锁的业务场景会更多,综合比较了业界基于各种

  • SQL语句中JOIN的用法场景分析

    记录:256 写SQL最高境界:SELECT * FROM 表名.当然这是一句自嘲.探究一下SQL语句中JOIN的用法,直到经历这个场景,变得想验证一下究竟. 一.场景 把关系型数据库A中表TEST_TB01和TEST_TB02迁移到大数据平台M(MaxCompute大数据平台).TEST_TB01单表1000万条记录,TEST_TB02单表80万条记录. 在关系型数据库中,TEST_TB01和TEST_TB02中有主键约束.在产生新增业务数据时,不会存在重复数据插入.但是,当数据迁移到大数据平

  • React Hooks钩子中API的使用示例分析

    目录 hooks是什么 Hooks的作用 使用Hooks组件前后开发模式的对比 Hooks使用策略 为什么要有Hooks useState useEffect使用 useEffect依赖项 使用情景 useMemo使用 useMemo缓存组件方式 useMemo和useEffect的区别 useCallback使用 useContext使用 useRef使用 为什么在函数组件中无法使用ref 如何在类组件中使用ref属性 自定义hooks hooks是什么 hooks理解字面意思就是钩子,是一些

  • JDK1.8中的ConcurrentHashMap使用及场景分析

    ConcurrentHashMap 的初步使用及场景: ConcurrentHashMap 是 J.U.C 包里面提供的一个线程安全并且高效的 HashMap,所以ConcurrentHashMap 在并发编程的场景中使用的频率比较高,那么我们就从ConcurrentHashMap 的使用上以及源码层面来分析 ConcurrentHashMap 到底是如何实现安全性的 api 使用: ConcurrentHashMap 是 Map 的派生类,所以 api 基本和 Hashmap 是类似,主要就是

  • java中ThreadLocal的应用场景实例分析

    说到线程的安全,我们可以通过ThreadLocal来解决.但作为一种强大的变量,它的应用场景远不止如此.在各类的框架中,我们依然可以使用来对它们进行管理.同时在使用ThreadLocal时需要注意内存泄漏的问题.下面我们就这两点进行分析,并带来对应代码的展示. 1.各种框架中的应用 Spring框架的事务管理中使用ThreadLocal来管理连接,每个线程是单独的连接,当事务失败时不能影响到其他线程的事务过程或结果,还有大家耳闻目睹的ORM框架.Mybatis也是用ThreadLocal管理,S

随机推荐