React高级概念之Context用法详解

 更新时间:2023年06月16日 09:15:48   作者:何遇er  
在React应用中,为了让数据在组件间共享,常见的方式是让它们以props的形式自顶向下传递,如果数据要在组件树不同层级共享,那么这些数据必须逐层传递直到目的地,Context如同管道,它将数据从入口直接传递到出口,使用Context能避免“prop-drilling”

Context 的基本用法

总体而言,使用 Context 分为如下三步:

创建 Context 对象

Context 只能使用 React.createContext 方法创建,代码如下:

// 注释Context中数据的类型
interface IMyContext {
    lang: string;
    changeLang: (lang: string) => void
}
// React.createContext的参数是Context中数据的默认值。
const MyContext = React.createContext<IMyContext >({
    lang: 'zh_CN',
    changeLang: () => { throw Error('你必须自己实现这个方法') }
})

用创建的 Context.Provider 包裹组件树。

用 Context.Provider 圈选 Context 的作用域,只有作用域内的组件才能消费 Context 中的数据,此处是管道的入口,在这里放入想要传递的数据。代码如下:

import { MyContext } from './myContext'
class ContextDemo extends React.Component<{}> {
    render() {
        return (
            <MyContext.Provider
                value={someValue} // 放入数据,它的数据类型必须与IMyContext接口兼容
            >
                // children
            </GlobalContext.Provider>
        )
    }
}

订阅 Context

此处是管道的出口,对于 Context 对象而言,管道入口只有一个,但出口可以有多个。订阅 Context 有多种方式,总体而言有如下三种:

类组件的静态属性 contextType

只能在类组件中使用,并且只能订阅一个 Context。用法如下:

class MyNestedClass extends React.Component<{}> {
    static contextType = MyContext // 订阅第一步创建的Context 
    render() {/**todo*/}
}

在类组件中使用 contextType 订阅 Context 之后,除了不能在构造函数中使用 this.context 访问到数据之外,在类组件的其他位置都能使用 this.context 访问到数据。生命周期 shouldComponentUpdate 的第三个参数是组件即将接收的 context。

useContext

在函数组件中通过 useContext 订阅 Context,useContext 的使用次数不限。用法如下:

function MyNestedFunc() {
  const myContext = useContext(MyContext) // 订阅第一步创建的Context
  return (/**todo*/)
}

Context.Consumer

它是组件,在 Context 作用域任何位置都能使用它,它只有一个名为 children 的 prop,children 必须是一个返回 React.ReactNode 的函数,该函数接收当前的 context 作为参数,用法如下:

<MyContext.Consumer>
    {(context) => <MyNestedCom lang={context.lang}/>}
</MyContext.Consumer>

Context + useReducer

Context + useReducer 指的是用 useReducer 管理状态,用 Context 传递值。与 Context 基本用法相比需要变化的是第二步,示例代码如下:

// context要传递的数据类型
interface IStyleContext {
    theme: 'light' | 'dark';
    size: 's' | 'm' | 'l';
    changeTheme: (theme: 'light' | 'dark') => void;
    changeSize: (size: 's' | 'm' | 'l') => void;
}
function ProviderCom() {
 // 用 useReducer 创建状态
  const [style, dispatch] = useReducer(reducer, {theme: 'light', size: 'm'})
  // 避免 ContextVal 被频繁新建
  const ContextVal = useMemo<IStyleContext>(() => {
    return {
      theme: style.theme,
      size: style.size,
      changeSize: (size: IStyleContext['size']) => dispatch({type: 'size', payload: size}),
      changeTheme: (theme: IStyleContext['theme']) => dispatch({type: 'theme', payload: theme})
    }
  }, [style.size, style.theme])
  return (
    <StyleContext.Provider value={ContextVal}> // 将要传递的数据放到 Context 中
      {/* todo */}
    </StyleContext.Provider>
  )
}

在上述示例中,状态由 useReducer 创建,被 reducer 函数更新,StyleContext 只负责传递数据,被 StyleContext.Provider 包裹的组件能订阅 StyleContext。

总结

只要 context value 被更新,那么订阅该 context 的组件一定会重新渲染,而不管 context value中更新的那部分值是否被它使用,也不管它的祖先组件是否跳过重新渲染,所以推荐将不同职责的数据保存到不同的 context 中,以减少不必要的重新渲染。

如果 Context.Provider 的 value 属性传递了一个对象字面量,那么 Context.Provider 的父组件每一次重新渲染都会使 context value 更新,进而导致订阅该 context 的组件重新渲染,所有应该避免给 Context.Provider 的 value 传对象字面量。

以上就是React高级概念之Context用法详解的详细内容,更多关于React Context用法的资料请关注脚本之家其它相关文章!

相关文章

  • 简易的redux createStore手写实现示例

    简易的redux createStore手写实现示例

    这篇文章主要介绍了简易的redux createStore手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • React Native之prop-types进行属性确认详解

    React Native之prop-types进行属性确认详解

    本篇文章主要介绍了React Native之prop-types进行属性确认详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • React创建组件的的方式汇总

    React创建组件的的方式汇总

    React 是一个用于构建用户界面的 JAVASCRIPT 库。这篇文章主要介绍了React组件的两种创建方式,一种是使用函数创建组件另一种是使用类创建组件,需要的朋友可以参考下
    2021-11-11
  • React表单容器的通用解决方案

    React表单容器的通用解决方案

    本文主要介绍了React表单容器的通用解决方案,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • 详解对于React结合Antd的Form组件实现登录功能

    详解对于React结合Antd的Form组件实现登录功能

    这篇文章主要介绍了详解对于React结合Antd的Form组件实现登录功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • 手把手教你从零开始react+antd搭建项目

    手把手教你从零开始react+antd搭建项目

    本文将从最基础的项目搭建开始讲起,做一个基于react和antd的后台管理系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • React Native系列之Recyclerlistview使用详解

    React Native系列之Recyclerlistview使用详解

    这篇文章主要为大家介绍了React Native系列之Recyclerlistview使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • react中antd Upload手动上传的示例

    react中antd Upload手动上传的示例

    本文主要介绍了react中antd Upload手动上传的示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • 浅谈React中组件逻辑复用的那些事儿

    浅谈React中组件逻辑复用的那些事儿

    这篇文章主要介绍了浅谈React中组件逻辑复用的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • React中refs的一些常见用法汇总

    React中refs的一些常见用法汇总

    Refs是一个 获取 DOM节点或React元素实例的工具,在React中Refs 提供了一种方式,允许用户访问DOM 节点或者在render方法中创建的React元素,这篇文章主要给大家介绍了关于React中refs的一些常见用法,需要的朋友可以参考下
    2021-07-07

最新评论