React Context 与 Zustand Store 集成方案

引言

在现代 React 应用开发中,状态管理一直是开发者面临的核心挑战之一。虽然 Redux 曾是主流解决方案,但其繁琐的样板代码让许多开发者望而却步。Zustand 作为一个轻量级的状态管理库,提供了更简洁的 API 和更好的 TypeScript 支持,同时还能与 React Context 无缝集成。

核心概念解析

Zustand 基础

Zustand 的核心是 createStore 函数,它创建一个状态存储 (store)。与 Redux 不同,Zustand 的 store 不需要额外的 reducer 或 action 定义。

import { createStore } from 'zustand';

const useBearStore = createStore((set) => ({
  bears: 0,
  increasePopulation: () => set((s) => ({ bears: s.bears + 1 })),
}))

React Context 集成

在大型应用中,我们经常需要将 Zustand store 与 React Context 结合使用,以便在组件树中共享状态。下面的代码展示了一个典型的集成模式:

  1. 创建 Context
  2. 定义 store 类型和创建函数
  3. 创建 Provider 组件
  4. 创建自定义 Hook 来访问 store

代码

类型定义与 Store 创建

interface PageProps {
  bears: number;
}

interface PageState extends PageProps {
  addBear: () => void;
}

function createPageStore(initProps?: Partial<PageState>) {
  const DEFAULT_PROPS: PageProps = {
    bears: 0,
  };

  return createStore<PageState>()((set) => ({
    ...DEFAULT_PROPS,
    ...initProps,
    addBear: () => {
      set((s) => ({ bears: 1 }));
    },
  }));
}

type PageStore = ReturnType<typeof createPageStore>;

这里定义了组件的 props 接口 (PageProps)、扩展后的状态接口 (PageState),以及 store 类型 (PageStore)。这种类型定义方式确保了完整的 TypeScript 支持。

Provider 组件实现

export function PageProvider({ children, ...props }: PageProviderProps) {
  const storeRef = useRef<PageStore>();
  if (!storeRef.current) {
    storeRef.current = createPageStore(props);
  }
  return <PageContext.Provider value={storeRef.current}>{children}</PageContext.Provider>;
}

Provider 组件使用 useRef 来保持 store 的稳定性,避免不必要的重新创建。这是性能优化的关键点。

自定义 Hook 访问

export function usePageContext<T>(selector: (state: PageState) => T): T {
  const store = useContext(PageContext);
  if (!store) throw new Error('Missing PageContext.Provider in the tree');
  return useStore(store, selector);
}

这个自定义 Hook 封装了 Context 访问和 Zustand 的 useStore Hook,提供了类型安全的 selector 功能。

实际应用示例

初始化状态

export default function Page() {
  return (
    <PageProvider bears={2}>
      <BearCounter />
      <Controls />
    </PageProvider>
  );
}

组件中使用状态

function BearCounter() {
  const bears = usePageContext((s) => s.bears);
  return <div>{bears} bears around here</div>;
}

function Controls() {
  const addBear = usePageContext((s) => s.addBear);
  return <button onClick={addBear}>Add bear</button>;
}

性能优化技巧

  1. 细粒度订阅:Zustand 会自动进行浅比较,只在你选择的 state 部分发生变化时触发重新渲染
  2. 稳定引用:确保 store 创建只发生一次,使用 useRef 来保持引用
  3. 选择器优化:尽量使用简单的选择器函数,避免在渲染时进行复杂计算

总结

  1. 对于小型应用,直接使用单个 Zustand 即可
  2. 对于多模块的中大型应用,合理拆分 store,避免单一 store 过于庞大。比如,你只是想为一个营销活动页面设计一个 store,可以采用本文的模式
  3. 始终为你的状态定义清晰的类型

通过这种模式,你可以在享受 Zustand 简洁 API 的同时,获得 React Context 提供的组件树隔离能力,为你的应用构建灵活且高效的状态管理系统。

posted @ 2025-08-06 13:57  guangzan  阅读(100)  评论(0)    收藏  举报