[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-4509042f-b8b8-44cd-9e2e-8452228d8b3a":3,"$fQqhYl2cJK5CHGg5M69jKuChn-cqd4kucY5vklRAGTDY":43},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":34},"4509042f-b8b8-44cd-9e2e-8452228d8b3a","react-state-management","精通Redux Toolkit、Zustand、Jotai和React Query的现代React状态管理。用于设置全局状态、管理服务器状态或选择状态管理解决方案时使用。","cat_coding_frontend","mod_coding","sickn33,coding","---\nname: react-state-management\ndescription: \"Master modern React state management with Redux Toolkit, Zustand, Jotai, and React Query. Use when setting up global state, managing server state, or choosing between state management solutions.\"\nrisk: unknown\nsource: community\ndate_added: \"2026-02-27\"\n---\n\n# React State Management\n\nComprehensive guide to modern React state management patterns, from local component state to global stores and server state synchronization.\n\n## Do not use this skill when\n\n- The task is unrelated to react state management\n- You need a different domain or tool outside this scope\n\n## Instructions\n\n- Clarify goals, constraints, and required inputs.\n- Apply relevant best practices and validate outcomes.\n- Provide actionable steps and verification.\n- If detailed examples are required, open `resources\u002Fimplementation-playbook.md`.\n\n## Use this skill when\n\n- Setting up global state management in a React app\n- Choosing between Redux Toolkit, Zustand, or Jotai\n- Managing server state with React Query or SWR\n- Implementing optimistic updates\n- Debugging state-related issues\n- Migrating from legacy Redux to modern patterns\n\n## Core Concepts\n\n### 1. State Categories\n\n| Type | Description | Solutions |\n|------|-------------|-----------|\n| **Local State** | Component-specific, UI state | useState, useReducer |\n| **Global State** | Shared across components | Redux Toolkit, Zustand, Jotai |\n| **Server State** | Remote data, caching | React Query, SWR, RTK Query |\n| **URL State** | Route parameters, search | React Router, nuqs |\n| **Form State** | Input values, validation | React Hook Form, Formik |\n\n### 2. Selection Criteria\n\n```\nSmall app, simple state → Zustand or Jotai\nLarge app, complex state → Redux Toolkit\nHeavy server interaction → React Query + light client state\nAtomic\u002Fgranular updates → Jotai\n```\n\n## Quick Start\n\n### Zustand (Simplest)\n\n```typescript\n\u002F\u002F store\u002FuseStore.ts\nimport { create } from 'zustand'\nimport { devtools, persist } from 'zustand\u002Fmiddleware'\n\ninterface AppState {\n  user: User | null\n  theme: 'light' | 'dark'\n  setUser: (user: User | null) => void\n  toggleTheme: () => void\n}\n\nexport const useStore = create\u003CAppState>()(\n  devtools(\n    persist(\n      (set) => ({\n        user: null,\n        theme: 'light',\n        setUser: (user) => set({ user }),\n        toggleTheme: () => set((state) => ({\n          theme: state.theme === 'light' ? 'dark' : 'light'\n        })),\n      }),\n      { name: 'app-storage' }\n    )\n  )\n)\n\n\u002F\u002F Usage in component\nfunction Header() {\n  const { user, theme, toggleTheme } = useStore()\n  return (\n    \u003Cheader className={theme}>\n      {user?.name}\n      \u003Cbutton onClick={toggleTheme}>Toggle Theme\u003C\u002Fbutton>\n    \u003C\u002Fheader>\n  )\n}\n```\n\n## Patterns\n\n### Pattern 1: Redux Toolkit with TypeScript\n\n```typescript\n\u002F\u002F store\u002Findex.ts\nimport { configureStore } from '@reduxjs\u002Ftoolkit'\nimport { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'\nimport userReducer from '.\u002Fslices\u002FuserSlice'\nimport cartReducer from '.\u002Fslices\u002FcartSlice'\n\nexport const store = configureStore({\n  reducer: {\n    user: userReducer,\n    cart: cartReducer,\n  },\n  middleware: (getDefaultMiddleware) =>\n    getDefaultMiddleware({\n      serializableCheck: {\n        ignoredActions: ['persist\u002FPERSIST'],\n      },\n    }),\n})\n\nexport type RootState = ReturnType\u003Ctypeof store.getState>\nexport type AppDispatch = typeof store.dispatch\n\n\u002F\u002F Typed hooks\nexport const useAppDispatch: () => AppDispatch = useDispatch\nexport const useAppSelector: TypedUseSelectorHook\u003CRootState> = useSelector\n```\n\n```typescript\n\u002F\u002F store\u002Fslices\u002FuserSlice.ts\nimport { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs\u002Ftoolkit'\n\ninterface User {\n  id: string\n  email: string\n  name: string\n}\n\ninterface UserState {\n  current: User | null\n  status: 'idle' | 'loading' | 'succeeded' | 'failed'\n  error: string | null\n}\n\nconst initialState: UserState = {\n  current: null,\n  status: 'idle',\n  error: null,\n}\n\nexport const fetchUser = createAsyncThunk(\n  'user\u002FfetchUser',\n  async (userId: string, { rejectWithValue }) => {\n    try {\n      const response = await fetch(`\u002Fapi\u002Fusers\u002F${userId}`)\n      if (!response.ok) throw new Error('Failed to fetch user')\n      return await response.json()\n    } catch (error) {\n      return rejectWithValue((error as Error).message)\n    }\n  }\n)\n\nconst userSlice = createSlice({\n  name: 'user',\n  initialState,\n  reducers: {\n    setUser: (state, action: PayloadAction\u003CUser>) => {\n      state.current = action.payload\n      state.status = 'succeeded'\n    },\n    clearUser: (state) => {\n      state.current = null\n      state.status = 'idle'\n    },\n  },\n  extraReducers: (builder) => {\n    builder\n      .addCase(fetchUser.pending, (state) => {\n        state.status = 'loading'\n        state.error = null\n      })\n      .addCase(fetchUser.fulfilled, (state, action) => {\n        state.status = 'succeeded'\n        state.current = action.payload\n      })\n      .addCase(fetchUser.rejected, (state, action) => {\n        state.status = 'failed'\n        state.error = action.payload as string\n      })\n  },\n})\n\nexport const { setUser, clearUser } = userSlice.actions\nexport default userSlice.reducer\n```\n\n### Pattern 2: Zustand with Slices (Scalable)\n\n```typescript\n\u002F\u002F store\u002Fslices\u002FcreateUserSlice.ts\nimport { StateCreator } from 'zustand'\n\nexport interface UserSlice {\n  user: User | null\n  isAuthenticated: boolean\n  login: (credentials: Credentials) => Promise\u003Cvoid>\n  logout: () => void\n}\n\nexport const createUserSlice: StateCreator\u003C\n  UserSlice & CartSlice, \u002F\u002F Combined store type\n  [],\n  [],\n  UserSlice\n> = (set, get) => ({\n  user: null,\n  isAuthenticated: false,\n  login: async (credentials) => {\n    const user = await authApi.login(credentials)\n    set({ user, isAuthenticated: true })\n  },\n  logout: () => {\n    set({ user: null, isAuthenticated: false })\n    \u002F\u002F Can access other slices\n    \u002F\u002F get().clearCart()\n  },\n})\n\n\u002F\u002F store\u002Findex.ts\nimport { create } from 'zustand'\nimport { createUserSlice, UserSlice } from '.\u002Fslices\u002FcreateUserSlice'\nimport { createCartSlice, CartSlice } from '.\u002Fslices\u002FcreateCartSlice'\n\ntype StoreState = UserSlice & CartSlice\n\nexport const useStore = create\u003CStoreState>()((...args) => ({\n  ...createUserSlice(...args),\n  ...createCartSlice(...args),\n}))\n\n\u002F\u002F Selective subscriptions (prevents unnecessary re-renders)\nexport const useUser = () => useStore((state) => state.user)\nexport const useCart = () => useStore((state) => state.cart)\n```\n\n### Pattern 3: Jotai for Atomic State\n\n```typescript\n\u002F\u002F atoms\u002FuserAtoms.ts\nimport { atom } from 'jotai'\nimport { atomWithStorage } from 'jotai\u002Futils'\n\n\u002F\u002F Basic atom\nexport const userAtom = atom\u003CUser | null>(null)\n\n\u002F\u002F Derived atom (computed)\nexport const isAuthenticatedAtom = atom((get) => get(userAtom) !== null)\n\n\u002F\u002F Atom with localStorage persistence\nexport const themeAtom = atomWithStorage\u003C'light' | 'dark'>('theme', 'light')\n\n\u002F\u002F Async atom\nexport const userProfileAtom = atom(async (get) => {\n  const user = get(userAtom)\n  if (!user) return null\n  const response = await fetch(`\u002Fapi\u002Fusers\u002F${user.id}\u002Fprofile`)\n  return response.json()\n})\n\n\u002F\u002F Write-only atom (action)\nexport const logoutAtom = atom(null, (get, set) => {\n  set(userAtom, null)\n  set(cartAtom, [])\n  localStorage.removeItem('token')\n})\n\n\u002F\u002F Usage\nfunction Profile() {\n  const [user] = useAtom(userAtom)\n  const [, logout] = useAtom(logoutAtom)\n  const [profile] = useAtom(userProfileAtom) \u002F\u002F Suspense-enabled\n\n  return (\n    \u003CSuspense fallback={\u003CSkeleton \u002F>}>\n      \u003CProfileContent profile={profile} onLogout={logout} \u002F>\n    \u003C\u002FSuspense>\n  )\n}\n```\n\n### Pattern 4: React Query for Server State\n\n```typescript\n\u002F\u002F hooks\u002FuseUsers.ts\nimport { useQuery, useMutation, useQueryClient } from '@tanstack\u002Freact-query'\n\n\u002F\u002F Query keys factory\nexport const userKeys = {\n  all: ['users'] as const,\n  lists: () => [...userKeys.all, 'list'] as const,\n  list: (filters: UserFilters) => [...userKeys.lists(), filters] as const,\n  details: () => [...userKeys.all, 'detail'] as const,\n  detail: (id: string) => [...userKeys.details(), id] as const,\n}\n\n\u002F\u002F Fetch hook\nexport function useUsers(filters: UserFilters) {\n  return useQuery({\n    queryKey: userKeys.list(filters),\n    queryFn: () => fetchUsers(filters),\n    staleTime: 5 * 60 * 1000, \u002F\u002F 5 minutes\n    gcTime: 30 * 60 * 1000, \u002F\u002F 30 minutes (formerly cacheTime)\n  })\n}\n\n\u002F\u002F Single user hook\nexport function useUser(id: string) {\n  return useQuery({\n    queryKey: userKeys.detail(id),\n    queryFn: () => fetchUser(id),\n    enabled: !!id, \u002F\u002F Don't fetch if no id\n  })\n}\n\n\u002F\u002F Mutation with optimistic update\nexport function useUpdateUser() {\n  const queryClient = useQueryClient()\n\n  return useMutation({\n    mutationFn: updateUser,\n    onMutate: async (newUser) => {\n      \u002F\u002F Cancel outgoing refetches\n      await queryClient.cancelQueries({ queryKey: userKeys.detail(newUser.id) })\n\n      \u002F\u002F Snapshot previous value\n      const previousUser = queryClient.getQueryData(userKeys.detail(newUser.id))\n\n      \u002F\u002F Optimistically update\n      queryClient.setQueryData(userKeys.detail(newUser.id), newUser)\n\n      return { previousUser }\n    },\n    onError: (err, newUser, context) => {\n      \u002F\u002F Rollback on error\n      queryClient.setQueryData(\n        userKeys.detail(newUser.id),\n        context?.previousUser\n      )\n    },\n    onSettled: (data, error, variables) => {\n      \u002F\u002F Refetch after mutation\n      queryClient.invalidateQueries({ queryKey: userKeys.detail(variables.id) })\n    },\n  })\n}\n```\n\n### Pattern 5: Combining Client + Server State\n\n```typescript\n\u002F\u002F Zustand for client state\nconst useUIStore = create\u003CUIState>((set) => ({\n  sidebarOpen: true,\n  modal: null,\n  toggleSidebar: () => set((s) => ({ sidebarOpen: !s.sidebarOpen })),\n  openModal: (modal) => set({ modal }),\n  closeModal: () => set({ modal: null }),\n}))\n\n\u002F\u002F React Query for server state\nfunction Dashboard() {\n  const { sidebarOpen, toggleSidebar } = useUIStore()\n  const { data: users, isLoading } = useUsers({ active: true })\n  const { data: stats } = useStats()\n\n  if (isLoading) return \u003CDashboardSkeleton \u002F>\n\n  return (\n    \u003Cdiv className={sidebarOpen ? 'with-sidebar' : ''}>\n      \u003CSidebar open={sidebarOpen} onToggle={toggleSidebar} \u002F>\n      \u003Cmain>\n        \u003CStatsCards stats={stats} \u002F>\n        \u003CUserTable users={users} \u002F>\n      \u003C\u002Fmain>\n    \u003C\u002Fdiv>\n  )\n}\n```\n\n## Best Practices\n\n### Do's\n- **Colocate state** - Keep state as close to where it's used as possible\n- **Use selectors** - Prevent unnecessary re-renders with selective subscriptions\n- **Normalize data** - Flatten nested structures for easier updates\n- **Type everything** - Full TypeScript coverage prevents runtime errors\n- **Separate concerns** - Server state (React Query) vs client state (Zustand)\n\n### Don'ts\n- **Don't over-globalize** - Not everything needs to be in global state\n- **Don't duplicate server state** - Let React Query manage it\n- **Don't mutate directly** - Always use immutable updates\n- **Don't store derived data** - Compute it instead\n- **Don't mix paradigms** - Pick one primary solution per category\n\n## Migration Guides\n\n### From Legacy Redux to RTK\n\n```typescript\n\u002F\u002F Before (legacy Redux)\nconst ADD_TODO = 'ADD_TODO'\nconst addTodo = (text) => ({ type: ADD_TODO, payload: text })\nfunction todosReducer(state = [], action) {\n  switch (action.type) {\n    case ADD_TODO:\n      return [...state, { text: action.payload, completed: false }]\n    default:\n      return state\n  }\n}\n\n\u002F\u002F After (Redux Toolkit)\nconst todosSlice = createSlice({\n  name: 'todos',\n  initialState: [],\n  reducers: {\n    addTodo: (state, action: PayloadAction\u003Cstring>) => {\n      \u002F\u002F Immer allows \"mutations\"\n      state.push({ text: action.payload, completed: false })\n    },\n  },\n})\n```\n\n## Resources\n\n- [Redux Toolkit Documentation](https:\u002F\u002Fredux-toolkit.js.org\u002F)\n- [Zustand GitHub](https:\u002F\u002Fgithub.com\u002Fpmndrs\u002Fzustand)\n- [Jotai Documentation](https:\u002F\u002Fjotai.org\u002F)\n- [TanStack Query](https:\u002F\u002Ftanstack.com\u002Fquery)\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,158,1187,"2026-05-16 13:36:35",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":32,"skillCount":33,"createdAt":26},"前端开发","frontend","mdi-language-html5","HTML\u002FCSS\u002FJavaScript\u002F框架相关",1,96,[35],{"id":36,"skillId":4,"version":37,"fileName":38,"fileSize":39,"filePath":40,"fileHash":41,"manifest":42,"createdAt":19},"71c39fe2-1eba-4621-a24c-a98137163a0f","1.0.0","react-state-management.zip",4503,"uploads\u002Fskills\u002F4509042f-b8b8-44cd-9e2e-8452228d8b3a\u002Freact-state-management.zip","bad2f05b1958dac3d8f132aa01d540ad4331f1527359b808a1507eb4e568f6b3","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":12232}]",{"code":44,"message":45,"data":46},200,"success",{"items":47,"stats":48,"page":51},[],{"averageRating":49,"totalRatings":49,"ratingCounts":50},0,[49,49,49,49,49],{"limit":52,"offset":49,"hasMore":53,"nextOffset":52,"ratedOnly":16},15,false]