状态管理Skill state-management

这是一个关于现代 React 应用状态管理的综合指南。它详细介绍了如何根据状态类型(服务器状态、客户端状态、表单状态、URL状态)选择和使用不同的状态管理库(TanStack Query, Zustand, React Hook Form, Zod, nuqs),以实现高效、类型安全且可维护的代码。内容包括查询键工厂、自定义钩子、类型化存储、性能优化选择器、状态持久化以及表单验证等核心模式。

前端开发 0 次安装 0 次浏览 更新于 3/2/2026

name: state-management description: TanStack Query + Zustand 模式。

状态管理

核心理念

  • 服务器状态 → TanStack Query
  • 客户端状态 → Zustand
  • 表单状态 → React Hook Form + Zod
  • URL 状态 → nuqs 或 searchParams

TanStack Query

查询键工厂模式

export const userKeys = {
  all: ['users'] as const,
  lists: () => [...userKeys.all, 'list'] as const,
  list: (filters: Filters) => [...userKeys.lists(), filters] as const,
  details: () => [...userKeys.all, 'detail'] as const,
  detail: (id: string) => [...userKeys.details(), id] as const,
};

钩子模式

export function useUsers(filters?: Filters) {
  return useQuery({
    queryKey: userKeys.list(filters ?? {}),
    queryFn: () => getUsers(filters),
  });
}

export function useUser(id: string) {
  return useQuery({
    queryKey: userKeys.detail(id),
    queryFn: () => getUser(id),
    enabled: !!id,
  });
}

export function useCreateUser() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: createUser,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: userKeys.lists() });
    },
  });
}

export function useUpdateUser() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: ({ id, data }: { id: string; data: UpdateUserInput }) =>
      updateUser(id, data),
    onSuccess: (_, { id }) => {
      queryClient.invalidateQueries({ queryKey: userKeys.detail(id) });
      queryClient.invalidateQueries({ queryKey: userKeys.lists() });
    },
  });
}

Zustand

类型化状态存储

interface UIStore {
  sidebarOpen: boolean;
  theme: 'light' | 'dark';
  toggleSidebar: () => void;
  setTheme: (theme: 'light' | 'dark') => void;
}

export const useUIStore = create<UIStore>((set) => ({
  sidebarOpen: true,
  theme: 'light',
  toggleSidebar: () => set((s) => ({ sidebarOpen: !s.sidebarOpen })),
  setTheme: (theme) => set({ theme }),
}));

性能优化:使用选择器

// 正确 - 仅在 sidebarOpen 变化时重新渲染
const sidebarOpen = useUIStore((s) => s.sidebarOpen);

// 错误 - 任何状态变化都会导致重新渲染
const { sidebarOpen } = useUIStore();

持久化中间件

import { persist } from 'zustand/middleware';

export const useSettingsStore = create<SettingsStore>()(
  persist(
    (set) => ({
      language: 'en',
      setLanguage: (language) => set({ language }),
    }),
    {
      name: 'settings-storage',
    }
  )
);

使用选择器计算派生值

// 创建一个选择器
const selectFilteredItems = (state: Store) =>
  state.items.filter(item => item.active);

// 在组件中使用
const filteredItems = useStore(selectFilteredItems);

表单状态:React Hook Form + Zod

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const schema = z.object({
  name: z.string().min(1, '必填项'),
  email: z.string().email('邮箱格式无效'),
});

type FormData = z.infer<typeof schema>;

export function UserForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    resolver: zodResolver(schema),
  });

  const onSubmit = (data: FormData) => {
    // data 是经过类型检查和验证的
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('name')} />
      {errors.name && <span>{errors.name.message}</span>}

      <input {...register('email')} />
      {errors.email && <span>{errors.email.message}</span>}

      <button type="submit">提交</button>
    </form>
  );
}