【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()
相关推荐
San30.17 小时前
深入理解 JavaScript:手写 `instanceof` 及其背后的原型链原理
开发语言·javascript·ecmascript
北冥有一鲲17 小时前
LangChain.js:RAG 深度解析与全栈实践
开发语言·javascript·langchain
用户289079421627118 小时前
Spec-Kit应用指南
前端
酸菜土狗18 小时前
🔥 手写 Vue 自定义指令:实现内容区拖拽调整大小(超实用)
前端
ohyeah18 小时前
深入理解 React Hooks:useState 与 useEffect 的核心原理与最佳实践
前端·react.js
Cache技术分享18 小时前
275. Java Stream API - flatMap 操作:展开一对多的关系,拉平你的流!
前端·后端
apollo_qwe19 小时前
前端缓存深度解析:从基础到进阶的实现方式与实践指南
前端
周星星日记19 小时前
vue中hash模式和history模式的区别
前端·面试
Light6019 小时前
Vue 高阶优化术:v-bind 与 v-on 的实战妙用与思维跃迁
前端·低代码·vue3·v-bind·组件封装·v-on·ai辅助开发
周星星日记19 小时前
5.为什么vue中使用query可以保留参数
前端·vue.js