[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6G3AZSCQ62BK2P52VAG49VR":3,"skill-same:01M6G3AZSCQ62BK2P52VAG49VR":67},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":40,"linkOnly":41,"markdownContent":42,"markdownBody":43,"frontMatter":44,"refName":35,"commitSha":46,"skillDirectory":47,"forksCount":14,"repositoryHtmlUrl":48,"repositoryHomepageUrl":6,"ownerHtmlUrl":49,"ownerBlogUrl":50,"ownerDescription":51,"updatedAt":52,"install":53,"resources":66},"01M6G3AZSCQ62BK2P52VAG49VR","react-state-management",null,"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.","reikiplanet\u002Fdaoskills","reikiplanet","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F96377599?v=4","01M6CVWCMD740YHQDK7E9QYBW4","Reiki Planet","01M6CVWCS4KXVA2CWFVJ43EAXK",0,"MIT","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fdevelopment\u002Freact-state-management\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],"react","state management","state","react state management","management","toolkit","server","zustand","global","use","up","master","community","query","jotai","with","2026-11-10 10:12:30",false,"---\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\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","# 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",{"name":5,"risk":45,"source":36,"description":7},"unknown","dff58085da947e81e8418c922055644bf0082b1b","skills\u002Fdevelopment\u002Freact-state-management","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills","https:\u002F\u002Fgithub.com\u002Freikiplanet","https:\u002F\u002Fwww.reiki-planet.com","Reiki Planet Game","2026-03-29 06:02:29",{"source":8,"skillName":5,"commands":54,"prompt":64,"zipAvailable":65},[55,58,61],{"tool":56,"command":57},"npx","npx skills add reikiplanet\u002Fdaoskills --skill react-state-management",{"tool":59,"command":60},"bunx","bunx skills add reikiplanet\u002Fdaoskills --skill react-state-management",{"tool":62,"command":63},"pnpm","pnpm dlx skills add reikiplanet\u002Fdaoskills --skill react-state-management","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fdevelopment\u002Freact-state-management\u002FSKILL.md",true,[],[68,94,106,120,139,162],{"skillNo":69,"name":70,"nameZh":6,"description":71,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":72,"categories":73,"keywords":74,"publishedAt":40},"01M6G614JTEQJHPT8AKK3YQ18S","web-games","Web browser game development principles. Framework selection, WebGPU, optimization, PWA.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fweb-games\u002FSKILL.md",[],[75,76,77,78,79,80,36,81,82,83,84,85,86,87,88,89,90,91,92,93],"games","web games","web","grep","principles","selection","framework selection","edit","write","read","pwa","game","web browser","game development","Optimization","framework","browser","development","webgpu",{"skillNo":95,"name":96,"nameZh":6,"description":97,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":100,"publishedAt":40},"01M6G611H2YGV0GZFP90D38ZMJ","vr-ar","VR\u002FAR development principles. Comfort, interaction, performance requirements.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fvr-ar\u002FSKILL.md",[],[101,102,92,103,104,36,82,83,84,78,105,79],"ar","vr ar","interaction","requirements","performance",{"skillNo":107,"name":108,"nameZh":6,"description":109,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":110,"categories":111,"keywords":112,"publishedAt":40},"01M6G60XNMHAMV1SV0EJ1CX0AY","templates","Project scaffolding templates for new applications. Use when creating new projects from scratch. Contains 12 templates for various tech stacks.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Ftemplates\u002FSKILL.md",[],[108,113,114,115,116,117,36,33,84,118,119,78],"project scaffolding","From Scratch","tech","project","scaffolding","projects","applications",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":126,"publishedAt":40},"01M6G60T0GATMK3Q5H8GDC1Z8S","wcag-audit-patterns","Conduct WCAG 2.2 accessibility audits with automated testing, manual verification, and remediation guidance. Use when auditing websites for accessibility, fixing WCAG violations, or implementing ac...","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsecurity\u002Fwcag-audit-patterns\u002FSKILL.md",[],[127,128,129,130,131,36,132,39,133,134,33,135,136,137,138],"wcag audit patterns","wcag audit","patterns","WCAG","audit","manual","automated testing","guidance","remediation","verification","accessibility","testing",{"skillNo":140,"name":141,"nameZh":6,"description":142,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":145,"publishedAt":40},"01M6G60PMCHW1FRZ63F931QK3R","vulnerability-scanner","Advanced vulnerability analysis principles. OWASP 2025, Supply Chain Security, attack surface mapping, risk prioritization.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsecurity\u002Fvulnerability-scanner\u002FSKILL.md",[],[146,147,148,149,150,151,152,153,36,84,78,154,79,155,156,157,158,159,160,161],"scanner","vulnerability scanner","vulnerability","prioritization","2025","mapping","chain","supply chain","Bash","analysis","risk","owasp","supply chain security","security","supply","advanced",{"skillNo":163,"name":164,"nameZh":6,"description":165,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":166,"categories":167,"keywords":168,"publishedAt":40},"01M6G60JZBB8DK0W3DSG1WNMZK","threat-modeling-expert","Expert in threat modeling methodologies, security architecture review, and risk assessment. Masters STRIDE, PASTA, attack trees, and security requirement extraction. Use for security architecture r...","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsecurity\u002Fthreat-modeling-expert\u002FSKILL.md",[],[169,170,171,172,173,174,175,176,159,33,177,178,179,36,180,181,182,156,183,184],"modeling","threat modeling expert","threat modeling","expert","threat","risk assessment","architecture review","architecture","security architecture review","trees","security architecture","security requirement extraction","assessment","extraction","review","stride"]