Yasin

Yasin

createContext-useContext-Context.Provider-usememo的用法

const BreakpointContext = createContext<BreakpointContextValue | null>(null);

export function BreakpointProvider({ children }: { children: ReactNode }) {
  const { width } = useWindowSize();
  const value = useMemo((): BreakpointContextValue => {
    const breakpoint: Breakpoint =
      width >= BREAKPOINTS["2xl"]
        ? "2xl"
        : width >= BREAKPOINTS.xl
          ? "xl"
          : width >= BREAKPOINTS.lg
            ? "lg"
            : width >= BREAKPOINTS.md
              ? "md"
              : "sm";

    return {
      breakpoint,
      width,
      isMobile: width < BREAKPOINTS.md,
      isTablet: width >= BREAKPOINTS.md && width < BREAKPOINTS.lg,
      isDesktop: width >= BREAKPOINTS.lg,
      isGreaterThan: (bp: Breakpoint) => width >= BREAKPOINTS[bp],
      isLessThan: (bp: Breakpoint) => width < BREAKPOINTS[bp],
    };
  }, [width]);
  return (
    <BreakpointContext.Provider value={value}>
      {children}
    </BreakpointContext.Provider>
  );
}

export function useBreakpointContext() {
  const context = useContext(BreakpointContext);
  if (!context) {
    throw new Error(
      "useBreakpointContext must be used within a BreakpointProvider",
    );
  }
  return context;
}
  1. createContext 和 useContext (上下文通信) 作用: React 通常是通过 Props 从父组件向子组件一层层传递数据。但在多层级嵌套时(例如从最外层传到最里层的按钮),一层层传非常麻烦(Props Drilling)。Context 就像一个传送门,允许你跨层级直接传递数据。

createContext: 用于创建这个传送门对象。

代码:const BreakpointContext = createContext<BreakpointContextValue | null>(null); 解释:不仅创建了 Context 对象,还定义了初始值(这里是 null)。 useContext: 用于接收传送门传来的数据。

代码:const context = useContext(BreakpointContext); 解释:在子组件(这里封装在 useBreakpointContext Hook 里)中,告诉 React "我要用 BreakpointContext 里的数据"。

  1. useMemo (性能优化) 作用: 用于缓存计算结果。只有当依赖项发生变化时,才会重新计算,否则直接使用缓存值。

代码分析:

为什么用它? 如果不用 useMemo,每次 BreakpointProvider 组件因为某些原因(比如父组件更新)重新渲染时,都会创建一个全新的 value 对象。 在 React 中,{ a: 1 } !== { a: 1 } (引用不同)。 如果 value 的引用变了,所有使用了这个 Context 的子组件都会被迫重新渲染,即使宽度根本没变。 效果: 只有当 width 发生变化时,才会重新计算 value 对象,避免不必要的性能浪费。3. 为什么 Return 的是 BreakpointContext.Provider 原因: createContext 创建出的对象包含两个主要属性:Provider (提供者) 和 Consumer (消费者)。

<BreakpointContext.Provider> 是数据的发射站。 它有一个必填的 value 属性。凡是被包裹在 <BreakpointContext.Provider> 标签内部的组件(即 {children}),都可以通过 useContext 读取到这个 value。 代码逻辑梳理:

创建上下文: createContext 定义数据结构。 计算数据: BreakpointProvider 组件内部利用 useWindowSize 获取宽,用 useMemo 算出当前的断点状态(value)。 广播数据: 通过 return <BreakpointContext.Provider value={value}> 将算好的数据“广播”给所有的子节点(children)。