【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()
相关推荐
Coderfuu11 分钟前
Java Web 3 Axios & Vue组件库
前端·javascript·vue.js
闭上眼让寒冷退却15 分钟前
axios笔记
前端·笔记
小C好好干饭16 分钟前
Vue网页屏保
前端·javascript·vue.js
叶浩成52018 分钟前
draggable插件——实现元素的拖动排序——拖动和不可拖动的两种情况处理
前端·javascript·vue.js
刘大浪21 分钟前
vue npm install出现问题
前端·vue.js·npm
素质白嫖怪25 分钟前
element Plus中 el-table表头宽度自适应,不换行
前端·javascript·vue.js
ethan.Yin31 分钟前
flex: 1 & display:flex 导致的宽度失效问题
javascript·css·css3·css flex·宽度失效
嘿,小苹果34 分钟前
Vue3技术开发,使用纯CSS3动手制作一个3D环绕的相册展示效果,支持传入任意图片.3D轮播相册的组件
前端·3d·css3
guokanglun1 小时前
css实现圆周运动效果
前端·css
MaxCosmos20011 小时前
挑战用React封装100个组件【009】
前端·javascript·react.js·typescript·前端框架