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;
}
- 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 里的数据"。
- 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)。
