React 状态管理工具之useContext

202 阅读3分钟

useContext是React提供的一个hook,它让你能够使用React的上下文特性来访问父组件提供的数据。上下文特性允许你在组件树中传递数据,而不需要通过props逐层传递。

代码结构分析

以下代码结构是用于useContext案例展示,方便理解,当熟悉之后,我们开始接下来的学习。

image.png

基本使用

1.创建 Context

​ 使用 React.createContext 创建一个 Context 对象。可以传递一个默认值,这个默认值会在没有 Provider 包裹时使用。高亮的这句话会在介绍完Api后详细介绍。

  • 基本语法:
const MyContext = React.createContext(defaultValue);

React.createContext 类似于一个store,类似于vuex,pinia创建了一个第三方中间状态管理仓库,一般都是定义在一个单独的js文件中。代码示例如下:

//useThemeContext.ts
import React from 'react'

const useThemeContext = React.createContext('default')
export default useThemeContext

2.提供 Context

​ 使用 MyContext.Provider 来包裹需要共享数据的组件,并通过 value 属性传递数据。

  • 基本语法:
<MyContext.Provider value={sharedData}>
  <MyComponent />
</MyContext.Provider>

​ 代码示例如下:

//Root.tsx

import { FC, useState } from 'react'
import useThemeContext from './useThemeContext' // 创建好的 Context 对象

// components -子组件
import CardItem from './CardItem.tsx'

const Root: FC = () => {
  return (
    <useThemeContext.Provider value={{ name: 'Person', age: 20 }}> //使用 MyContext.Provider 传递值
      <div>我是父组件</div>
      我是子组件
      <CardItem></CardItem>
    </useThemeContext.Provider>
  )
}

export default Root

3.消费/使用Context

​ 使用context方式有两种,一种是MyContext.Consumer,另一种就是使用useContext的hooks,下面我们都会介绍。

​ 第一种:

​ 使用 MyContext.Consumer来包裹需要共享数据的组件,并通过 value 属性传递数据。

<MyContext.Consumer>
  {value => (
    // 根据 context 值渲染的 JSX
  )}
</MyContext.Consumer>

​ 代码示例如下:

//CardItem.tsx

import { Card, Space } from 'antd'

import useThemeContext from './useThemeContext' // 创建好的 Context 对象

const CardItem = () => {
  return (
    <useThemeContext.Consumer> //使用MyContext.Consumer 获得context
      {(ctx: any) => (
        <>
            <Card>
              <p>{ctx.name}</p>
            </Card>
        </>
      )}
    </useThemeContext.Consumer>
  )
}

export default CardItem

第二种: ​ 使用useContext获取context

  • 基本语法
const value = useContext(MyContext);

​ 代码示例如下:

//CardItem.tsx

import { Card, Space } from 'antd'
import useThemeContext from './useThemeContext' // 假设 useThemeContext 导出了 ThemeContext
import { useContext } from 'react'

const CardItem = () => {
  const ctx = useContext(useThemeContext) //使用hooks获取
  return (
    <>
        <Card>
          <p>{ctx.name}</p>
        </Card>
    </>
  )
}

export default CardItem

还记得我们刚开始介绍所说的

"使用 React.createContext 创建一个 Context 对象。可以传递一个默认值,这个默认值会在没有 Provider 包裹时使用。"

当我们没有使用MyContext.Provider方式提供数据的时候时候,我们使用useContext获取到的值就是createContext(defaultValue)_的defaultValue。

React useContext 总结

主要的 API

  1. React.createContext:

    • 创建一个 Context 对象,可以传递一个默认值。
    • 基本语法:
      const MyContext = React.createContext(defaultValue);
      
  2. MyContext.Provider:

    • 使用 Provider 来包裹需要共享数据的组件,并通过 value 属性传递数据。
    • 基本语法:
      <MyContext.Provider value={sharedData}>
        <MyComponent />
      </MyContext.Provider>
      
  3. MyContext.Consumer:

    • 使用 Consumer 来包裹需要共享数据的组件,通过函数作为子组件的方式访问 Context 值。
    • 基本语法:
      <MyContext.Consumer>
        {value => (
          // 根据 context 值渲染的 JSX
        )}
      </MyContext.Consumer>
      
  4. useContext:

    • 使用 useContext hook 来获取 Context 值。
    • 基本语法:
      const value = useContext(MyContext);
      

不常用的 API

  1. Context.displayName:

    • displayName 是一个可以给 Context 对象设置显示名称的属性,有助于在 React DevTools 中显示更友好的调试信息。
    • 基本语法:
      const MyContext = React.createContext();
      MyContext.displayName = 'MyContextDisplayName';
      
  2. Context.Consumer 作为 Render Props:

    • 虽然 Consumer 常用于函数子组件,但它也可以直接用作组件的一部分,这种用法相对不常见。
    • 用法示例:
      <MyContext.Consumer>
        {value => <MyComponent value={value} />}
      </MyContext.Consumer>