【React】createContext 和 useContext

createContext

createContext 创建一个上下文对象,可以用于在组件树中共享数据,而不必通过 props 手动传递。

createContext() 会返回一个上下文对象,其中包含两个重要属性:

  • Provider: 用于提供上下文的组件。
  • Consumer: 用于消费上下文的组件。

Provider 提供数据

javascript 复制代码
import React, { createContext, useState } from 'react';

// 创建一个 Context上下文对象
const MyContext = createContext();

const MyProvider = ({ children }) => {
    const [value, setValue] = useState('Hello World');

    return (
        <MyContext.Provider value={{ value, setValue }}>
            {children}
        </MyContext.Provider>
    );
};

export { MyProvider, MyContext };

通常放在顶级组件

javascript 复制代码
<MyProvider>
    <App />
</MyProvider>

Consumer 使用数据

javascript 复制代码
const MyComponentUsingConsumer = () => {
    return (
        <MyContext.Consumer>
            {({ value, setValue }) => (
                <div>
                    <p>{value}</p>
                    <button onClick={() => setValue('New Value from Consumer')}>
                        Change Value
                    </button>
                </div>
            )}
        </MyContext.Consumer>
    );
};

useContext

获取上下文对象,可以理解为简化版的 Consumer,可以直接从上下文对象中解构出 数据。

javascript 复制代码
import { useContext } from 'react';

const MyComponentUsingHook = () => {
    const { value, setValue } = useContext(MyContext);

    return (
        <div>
            <p>{value}</p>
            <button onClick={() => setValue('New Value from useContext')}>
                Change Value
            </button>
        </div>
    );
};

应用场景

如实时监听窗口大小

javascript 复制代码
import React, {
  createContext,
  useContext,
  useEffect,
  useState,
  ReactNode,
} from "react"

// 定义上下文的类型
interface SizeData {
  width: number
  height: number
  isLarge: boolean
}

// 创建上下文并设置默认值为 SizeData 类型
const MyContext = createContext<SizeData | undefined>(undefined)

interface MyProviderProps {
  children: ReactNode
}

// 创建 Provider 组件
export const MyProvider: React.FC<MyProviderProps> = ({ children }) => {
  const isLarge = () => window.innerWidth > 1024

  const [sizeData, setSizeData] = useState<SizeData>({
    width: window.innerWidth,
    height: window.innerHeight,
    isLarge: isLarge(),
  })

  useEffect(() => {
    let timer: number
    const handler = () => {
      clearTimeout(timer)
      timer = setTimeout(() => {
        setSizeData({
          width: window.innerWidth,
          height: window.innerHeight,
          isLarge: isLarge(),
        })
      }, 200)
    }

    window.addEventListener("resize", handler)
    return () => {
      window.removeEventListener("resize", handler)
      clearTimeout(timer)
    }
  }, [])

  return <MyContext.Provider value={sizeData}>{children}</MyContext.Provider>
}

// 创建自定义 Hook
export const useSize = (): SizeData => {
  const context = useContext(MyContext)

  // 处理 context 为 undefined 的情况
  if (!context) {
    throw new Error("useSize must be used within a MyProvider")
  }

  return context
}

main.tsx

javascript 复制代码
createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <MyProvider>
      <App />
    </MyProvider>
  </StrictMode>
)

使用

javascript 复制代码
const { width, height, isLarge } = useSize()
相关推荐
毛骗导演14 分钟前
@tencent-weixin/openclaw-weixin 插件深度解析(四):API 协议与数据流设计
前端·架构
毛骗导演17 分钟前
@tencent-weixin/openclaw-weixin 插件深度解析(二):消息处理系统架构
前端·架构
IT_陈寒35 分钟前
深入理解JavaScript:核心原理与最佳实践
前端·人工智能·后端
MrGud40 分钟前
Cesium中的坐标系及其转换
前端·cesium
小付学代码41 分钟前
香港地图可编辑版
前端
兆子龙1 小时前
TypeScript高级类型编程:从入门到精通
前端·后端
SuperEugene1 小时前
Vue3 模板语法规范实战:v-if/v-for 不混用 + 表达式精简,避坑指南|Vue 组件与模板规范篇
开发语言·前端·javascript·vue.js·前端框架
IT_陈寒1 小时前
Python开发者的效率革命:这5个技巧让你的代码提速50%!
前端·人工智能·后端
Luna-player1 小时前
Vue 3 + Vue Router 的路由配置,简单示例
前端·javascript·vue.js
用户69371750013841 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能