{"id":"38d41dc8-8dc3-43ba-960f-512b9fe26547","shortId":"8xKJhf","kind":"skill","title":"state-management","tagline":"React Query and Zustand patterns for state management. Use when implementing data fetching, caching, mutations, or client-side state. Triggers on tasks involving useQuery, useMutation, Zustand stores, caching, or state management.","description":"# State Management with React Query + Zustand\n\n**Version 1.1.0** | TanStack Query v5 | Zustand v5 | March 2026\n\n> **Note:**\n> This document provides comprehensive patterns for AI agents and LLMs working with\n> TanStack Query v5 and Zustand v5. All examples are verified against v5 APIs.\n> Optimized for automated refactoring, code generation, and state management best practices.\n\n## v5 Breaking Changes (Quick Reference)\n\n**TanStack Query v5:**\n- `cacheTime` → `gcTime`\n- `keepPreviousData` option → `placeholderData: keepPreviousData` (imported helper)\n- `isPreviousData` → `isPlaceholderData`\n- `onSuccess`/`onError`/`onSettled` removed from `useQuery` — still valid on `useMutation`\n- `suspense: true` on `useQuery` removed → use `useSuspenseQuery`\n\n**Zustand v5:**\n- `shallow` as 2nd arg removed → `useShallow` from `zustand/shallow`\n- Selectors returning new references need `useShallow` to avoid infinite loops\n\n## Security: Persist Middleware\n\n> **Never persist auth tokens, passwords, or secrets to localStorage/sessionStorage.**\n> Use `partialize` to persist only non-sensitive state. Manage tokens via HttpOnly cookies.\n\n---\n\nComprehensive patterns for server state (React Query) and client state (Zustand). Contains 26+ rules for efficient data fetching and state management.\n\n## When to Apply\n\nReference these guidelines when:\n- Fetching data from APIs\n- Managing server state and caching\n- Handling mutations and optimistic updates\n- Creating client-side stores\n- Combining React Query with Zustand\n\n## Rule Categories by Priority\n\n| Priority | Category | Impact | Prefix |\n|----------|----------|--------|--------|\n| 1 | React Query Basics | CRITICAL | `rq-` |\n| 2 | Zustand Store Patterns | CRITICAL | `zs-` |\n| 3 | Caching & Invalidation | HIGH | `cache-` |\n| 4 | Mutations & Updates | HIGH | `mut-` |\n| 5 | Optimistic Updates | MEDIUM | `opt-` |\n| 6 | DevTools & Debugging | MEDIUM | `dev-` |\n| 7 | Advanced Patterns | LOW | `adv-` |\n\n## Quick Reference\n\n### 1. React Query Basics (CRITICAL)\n\n- `rq-setup` - QueryClient and Provider setup\n- `rq-usequery` - Basic useQuery patterns\n- `rq-querykeys` - Query key organization\n- `rq-loading-error` - Handle loading and error states\n- `rq-enabled` - Conditional queries\n\n### 2. Zustand Store Patterns (CRITICAL)\n\n- `zs-create-store` - Create basic store\n- `zs-typescript` - TypeScript store patterns\n- `zs-selectors` - Efficient selectors\n- `zs-actions` - Action patterns\n- `zs-persist` - Persist state to storage\n\n### 3. Caching & Invalidation (HIGH)\n\n- `cache-stale-time` - Configure stale time\n- `cache-gc-time` - Configure garbage collection\n- `cache-invalidation` - Invalidate queries\n- `cache-prefetch` - Prefetch data\n- `cache-initial-data` - Set initial data\n\n### 4. Mutations & Updates (HIGH)\n\n- `mut-usemutation` - Basic useMutation\n- `mut-callbacks` - onSuccess, onError callbacks\n- `mut-invalidate` - Invalidate after mutation\n- `mut-update-cache` - Direct cache updates\n\n### 5. Optimistic Updates (MEDIUM)\n\n- `opt-basic` - Basic optimistic updates\n- `opt-rollback` - Rollback on error\n- `opt-variables` - Use mutation variables\n\n### 6. DevTools & Debugging (MEDIUM)\n\n- `dev-react-query` - React Query DevTools\n- `dev-zustand` - Zustand DevTools\n- `dev-debugging` - Debug strategies\n\n### 7. Advanced Patterns (LOW)\n\n- `adv-infinite-queries` - Infinite scrolling\n- `adv-parallel-queries` - Parallel requests\n- `adv-dependent-queries` - Dependent queries\n- `adv-query-zustand` - Combine RQ with Zustand\n\n## React Query Patterns\n\n### Setup\n\n```tsx\n// lib/queryClient.ts\nimport { QueryClient } from '@tanstack/react-query'\n\nexport const queryClient = new QueryClient({\n  defaultOptions: {\n    queries: {\n      staleTime: 1000 * 60 * 5, // 5 minutes\n      gcTime: 1000 * 60 * 30,   // 30 minutes (formerly cacheTime)\n      retry: 1,\n      refetchOnWindowFocus: false,\n    },\n  },\n})\n\n// App.tsx\nimport { QueryClientProvider } from '@tanstack/react-query'\nimport { ReactQueryDevtools } from '@tanstack/react-query-devtools'\nimport { queryClient } from './lib/queryClient'\n\nfunction App() {\n  return (\n    <QueryClientProvider client={queryClient}>\n      <Router />\n      <ReactQueryDevtools initialIsOpen={false} />\n    </QueryClientProvider>\n  )\n}\n```\n\n### Query Keys Factory\n\n```tsx\n// lib/queryKeys.ts\nexport const queryKeys = {\n  // All posts\n  posts: {\n    all: ['posts'] as const,\n    lists: () => [...queryKeys.posts.all, 'list'] as const,\n    list: (filters: PostFilters) =>\n      [...queryKeys.posts.lists(), filters] as const,\n    details: () => [...queryKeys.posts.all, 'detail'] as const,\n    detail: (id: number) => [...queryKeys.posts.details(), id] as const,\n  },\n\n  // All users\n  users: {\n    all: ['users'] as const,\n    detail: (id: number) => [...queryKeys.users.all, id] as const,\n    posts: (userId: number) => [...queryKeys.users.all, userId, 'posts'] as const,\n  },\n}\n```\n\n### useQuery Hook\n\n```tsx\n// hooks/usePosts.ts\nimport { useQuery } from '@tanstack/react-query'\nimport { queryKeys } from '@/lib/queryKeys'\nimport { fetchPosts, fetchPost } from '@/api/posts'\n\nexport function usePosts(filters?: PostFilters) {\n  return useQuery({\n    queryKey: queryKeys.posts.list(filters ?? {}),\n    queryFn: () => fetchPosts(filters),\n  })\n}\n\nexport function usePost(id: number) {\n  return useQuery({\n    queryKey: queryKeys.posts.detail(id),\n    queryFn: () => fetchPost(id),\n    enabled: !!id, // Only run if id exists\n  })\n}\n\n// Usage in component\nfunction PostList() {\n  const { data: posts, isLoading, error } = usePosts()\n\n  if (isLoading) return <Spinner />\n  if (error) return <Error message={error.message} />\n\n  return (\n    <ul>\n      {posts?.map((post) => (\n        <li key={post.id}>{post.title}</li>\n      ))}\n    </ul>\n  )\n}\n```\n\n### useMutation Hook\n\n```tsx\n// hooks/useCreatePost.ts\nimport { useMutation, useQueryClient } from '@tanstack/react-query'\nimport { queryKeys } from '@/lib/queryKeys'\nimport { createPost } from '@/api/posts'\n\nexport function useCreatePost() {\n  const queryClient = useQueryClient()\n\n  return useMutation({\n    mutationFn: createPost,\n    onSuccess: (newPost) => {\n      // Invalidate and refetch posts list\n      queryClient.invalidateQueries({\n        queryKey: queryKeys.posts.lists(),\n      })\n    },\n    onError: (error) => {\n      console.error('Failed to create post:', error)\n    },\n  })\n}\n\n// Usage\nfunction CreatePostForm() {\n  const { mutate, isPending } = useCreatePost()\n\n  const handleSubmit = (data: CreatePostData) => {\n    mutate(data)\n  }\n\n  return (\n    <form onSubmit={handleSubmit}>\n      {/* form fields */}\n      <button disabled={isPending}>\n        {isPending ? 'Creating...' : 'Create'}\n      </button>\n    </form>\n  )\n}\n```\n\n### Optimistic Updates\n\n```tsx\nexport function useUpdatePost() {\n  const queryClient = useQueryClient()\n\n  return useMutation({\n    mutationFn: updatePost,\n    onMutate: async (updatedPost) => {\n      // Cancel outgoing refetches\n      await queryClient.cancelQueries({\n        queryKey: queryKeys.posts.detail(updatedPost.id),\n      })\n\n      // Snapshot previous value\n      const previousPost = queryClient.getQueryData(\n        queryKeys.posts.detail(updatedPost.id)\n      )\n\n      // Optimistically update\n      queryClient.setQueryData(\n        queryKeys.posts.detail(updatedPost.id),\n        updatedPost\n      )\n\n      return { previousPost }\n    },\n    onError: (err, updatedPost, context) => {\n      // Rollback on error\n      queryClient.setQueryData(\n        queryKeys.posts.detail(updatedPost.id),\n        context?.previousPost\n      )\n    },\n    onSettled: (data, error, variables) => {\n      // Refetch after settle\n      queryClient.invalidateQueries({\n        queryKey: queryKeys.posts.detail(variables.id),\n      })\n    },\n  })\n}\n```\n\n## Zustand Patterns\n\n### Basic Store\n\n```tsx\n// stores/useCounterStore.ts\nimport { create } from 'zustand'\n\ninterface CounterState {\n  count: number\n  increment: () => void\n  decrement: () => void\n  reset: () => void\n}\n\nexport const useCounterStore = create<CounterState>((set) => ({\n  count: 0,\n  increment: () => set((state) => ({ count: state.count + 1 })),\n  decrement: () => set((state) => ({ count: state.count - 1 })),\n  reset: () => set({ count: 0 }),\n}))\n\n// Usage\nfunction Counter() {\n  const { count, increment, decrement } = useCounterStore()\n\n  return (\n    <div>\n      <span>{count}</span>\n      <button onClick={increment}>+</button>\n      <button onClick={decrement}>-</button>\n    </div>\n  )\n}\n```\n\n### Store with TypeScript and Middleware\n\n```tsx\n// stores/useAuthStore.ts\nimport { create } from 'zustand'\nimport { persist, devtools } from 'zustand/middleware'\n\ninterface User {\n  id: number\n  name: string\n  email: string\n}\n\ninterface AuthState {\n  user: User | null\n  isAuthenticated: boolean\n  login: (user: User) => void\n  logout: () => void\n}\n\n// ✅ Never persist tokens to localStorage — use HttpOnly cookies server-side\nexport const useAuthStore = create<AuthState>()(\n  devtools(\n    persist(\n      (set) => ({\n        user: null,\n        isAuthenticated: false,\n\n        login: (user) =>\n          set({\n            user,\n            isAuthenticated: true,\n          }),\n\n        logout: () =>\n          set({\n            user: null,\n            isAuthenticated: false,\n          }),\n      }),\n      {\n        name: 'auth-storage',\n        // Only persist display info and auth flag — tokens must NOT be included\n        partialize: (state) => ({\n          user: state.user,\n          isAuthenticated: state.isAuthenticated,\n        }),\n      }\n    )\n  )\n)\n```\n\n### Selectors for Performance\n\n```tsx\n// Use selectors to prevent unnecessary re-renders\nfunction UserName() {\n  // Only re-renders when user.name changes\n  const name = useAuthStore((state) => state.user?.name)\n  return <span>{name}</span>\n}\n\n// Multiple selectors\nfunction UserInfo() {\n  const user = useAuthStore((state) => state.user)\n  const isAuthenticated = useAuthStore((state) => state.isAuthenticated)\n\n  if (!isAuthenticated) return <LoginButton />\n  return <span>{user?.name}</span>\n}\n```\n\n### Combining React Query + Zustand\n\n```tsx\n// Server state: React Query (what comes from API)\nconst { data: posts } = usePosts()\n\n// Client state: Zustand (UI state)\nconst { selectedPostId, selectPost } = useUIStore()\n\n// Use together\nconst selectedPost = posts?.find((p) => p.id === selectedPostId)\n```\n\n## How to Use\n\nRead individual rule files for detailed explanations and code examples:\n\n```\nrules/rq-usequery.md\nrules/rq-query-keys.md\nrules/rq-mutation-setup.md\nrules/rq-optimistic-updates.md\nrules/zs-create-store.md\nrules/zs-persist.md\nrules/rq-query-invalidation.md\nrules/rq-prefetching.md\n```\n\n---\n\n## References\n\n### React Query (TanStack Query)\n1. [TanStack Query Documentation](https://tanstack.com/query/latest)\n2. [React Query Overview](https://tanstack.com/query/latest/docs/react/overview)\n3. [Queries Guide](https://tanstack.com/query/latest/docs/react/guides/queries)\n4. [Mutations Guide](https://tanstack.com/query/latest/docs/react/guides/mutations)\n5. [Query Keys Guide](https://tanstack.com/query/latest/docs/react/guides/query-keys)\n6. [Optimistic Updates](https://tanstack.com/query/latest/docs/react/guides/optimistic-updates)\n7. [Infinite Queries](https://tanstack.com/query/latest/docs/react/guides/infinite-queries)\n8. [Paginated Queries](https://tanstack.com/query/latest/docs/react/guides/paginated-queries)\n9. [React Query DevTools](https://tanstack.com/query/latest/docs/react/devtools)\n\n### Zustand\n1. [Zustand Demo](https://zustand-demo.pmnd.rs)\n2. [Zustand GitHub](https://github.com/pmndrs/zustand)\n3. [Getting Started](https://docs.pmnd.rs/zustand/getting-started/introduction)\n4. [TypeScript Guide](https://docs.pmnd.rs/zustand/guides/typescript)\n5. [Persisting Store Data](https://docs.pmnd.rs/zustand/integrations/persisting-store-data)\n6. [Zustand Recipes](https://github.com/pmndrs/zustand#recipes)\n\n---\n\n## License\n\nThis skill is provided as-is for educational and development purposes. React Query is MIT licensed by TanStack. Zustand is MIT licensed by Poimandres (pmnd.rs).","tags":["state","management","agent","skills","asyrafhussin","agent-rules","agent-skills","ai-agents","ai-slop","claude-code","code-quality","code-review"],"capabilities":["skill","source-asyrafhussin","skill-state-management","topic-agent-rules","topic-agent-skills","topic-ai-agents","topic-ai-slop","topic-claude-code","topic-code-quality","topic-code-review","topic-codex","topic-cursor","topic-laravel","topic-nodejs","topic-react"],"categories":["agent-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/AsyrafHussin/agent-skills/state-management","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add AsyrafHussin/agent-skills","source_repo":"https://github.com/AsyrafHussin/agent-skills","install_from":"skills.sh"}},"qualityScore":"0.469","qualityRationale":"deterministic score 0.47 from registry signals: · indexed on github topic:agent-skills · 39 github stars · SKILL.md body (12,044 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:58:25.424Z","embedding":null,"createdAt":"2026-05-16T18:57:15.058Z","updatedAt":"2026-05-18T18:58:25.424Z","lastSeenAt":"2026-05-18T18:58:25.424Z","tsv":"'/api/posts':611,689 '/lib/queryclient':524 '/lib/querykeys':606,685 '/pmndrs/zustand#recipes)':1161 '/pmndrs/zustand)':1136 '/query/latest)':1074 '/query/latest/docs/react/devtools)':1125 '/query/latest/docs/react/guides/infinite-queries)':1112 '/query/latest/docs/react/guides/mutations)':1093 '/query/latest/docs/react/guides/optimistic-updates)':1106 '/query/latest/docs/react/guides/paginated-queries)':1118 '/query/latest/docs/react/guides/queries)':1087 '/query/latest/docs/react/guides/query-keys)':1100 '/query/latest/docs/react/overview)':1081 '/zustand/getting-started/introduction)':1142 '/zustand/guides/typescript)':1148 '/zustand/integrations/persisting-store-data)':1155 '0':832,848 '1':229,268,509,838,844,1068,1127 '1.1.0':43 '1000':495,501 '2':235,306,1075,1131 '2026':50 '26':181 '2nd':127 '3':241,341,1082,1137 '30':503,504 '4':246,376,1088,1143 '5':251,404,497,498,1094,1149 '6':256,426,1101,1156 '60':496,502 '7':261,447,1107 '8':1113 '9':1119 'action':331,332 'adv':265,452,458,464,470 'adv-dependent-queri':463 'adv-infinite-queri':451 'adv-parallel-queri':457 'adv-query-zustand':469 'advanc':262,448 'agent':59 'ai':58 'api':76,200,1019 'app':526 'app.tsx':512 'appli':192 'arg':128 'as-i':1167 'async':757 'auth':148,938,945 'auth-storag':937 'authstat':890 'autom':79 'avoid':140 'await':762 'basic':232,271,283,316,383,410,411,808 'best':86 'boolean':895 'break':89 'button':737,859,862 'cach':17,32,205,242,245,342,346,353,360,365,370,400,402 'cache-gc-tim':352 'cache-initial-data':369 'cache-invalid':359 'cache-prefetch':364 'cache-stale-tim':345 'cachetim':96,507 'callback':387,390 'cancel':759 'categori':222,226 'chang':90,978 'client':21,177,213,529,1024 'client-sid':20,212 'code':81,1053 'collect':358 'combin':216,473,1007 'come':1017 'compon':647 'comprehens':55,169 'condit':304 'configur':349,356 'console.error':712 'const':488,540,548,553,560,565,572,579,586,594,650,693,721,725,749,770,827,852,914,979,991,996,1020,1029,1035 'contain':180 'context':786,793 'cooki':168,909 'count':818,831,836,842,847,853,858 'counter':851 'counterst':817 'creat':211,313,315,715,741,742,813,829,873,916 'createpost':687,699 'createpostdata':728 'createpostform':720 'critic':233,239,272,310 'data':15,185,198,368,372,375,651,727,730,796,1021,1152 'debug':258,428,444,445 'decrement':822,839,855,864 'defaultopt':492 'demo':1129 'depend':465,467 'detail':561,563,566,580,1050 'dev':260,431,438,443 'dev-debug':442 'dev-react-queri':430 'dev-zustand':437 'develop':1173 'devtool':257,427,436,441,878,917,1122 'direct':401 'disabl':738 'display':942 'docs.pmnd.rs':1141,1147,1154 'docs.pmnd.rs/zustand/getting-started/introduction)':1140 'docs.pmnd.rs/zustand/guides/typescript)':1146 'docs.pmnd.rs/zustand/integrations/persisting-store-data)':1153 'document':53,1071 'educ':1171 'effici':184,327 'email':887 'enabl':303,638 'err':784 'error':295,299,419,654,660,662,711,717,789,797 'error.message':664 'exampl':71,1054 'exist':644 'explan':1051 'export':487,539,612,625,690,746,826,913 'factori':536 'fail':713 'fals':511,533,923,935 'fetch':16,186,197 'fetchpost':608,609,623,636 'field':736 'file':1048 'filter':555,558,615,621,624 'find':1038 'flag':946 'form':732,735 'former':506 'function':525,613,626,648,691,719,747,850,970,989 'garbag':357 'gc':354 'gctime':97,500 'generat':82 'get':1138 'github':1133 'github.com':1135,1160 'github.com/pmndrs/zustand#recipes)':1159 'github.com/pmndrs/zustand)':1134 'guid':1084,1090,1097,1145 'guidelin':195 'handl':206,296 'handlesubmit':726,734 'helper':103 'high':244,249,344,379 'hook':596,674 'hooks/usecreatepost.ts':676 'hooks/useposts.ts':598 'httpon':167,908 'id':567,570,581,584,628,634,637,639,643,883 'impact':227 'implement':14 'import':102,483,513,517,521,599,603,607,677,682,686,812,872,876 'includ':951 'increment':820,833,854,861 'individu':1046 'infinit':141,453,455,1108 'info':943 'initi':371,374 'initialisopen':532 'interfac':816,881,889 'invalid':243,343,361,362,393,394,702 'involv':27 'isauthent':894,922,928,934,956,997,1002 'isload':653,657 'ispend':723,739,740 'isplaceholderdata':105 'ispreviousdata':104 'keeppreviousdata':98,101 'key':290,535,670,1096 'li':669 'lib/queryclient.ts':482 'lib/querykeys.ts':538 'licens':1162,1179,1185 'list':549,551,554,706 'llms':61 'load':294,297 'localstorag':906 'localstorage/sessionstorage':154 'login':896,924 'logout':900,930 'loop':142 'low':264,450 'manag':3,11,35,37,85,164,189,201 'map':667 'march':49 'medium':254,259,407,429 'messag':663 'middlewar':145,869 'minut':499,505 'mit':1178,1184 'multipl':987 'must':948 'mut':250,381,386,392,398 'mut-callback':385 'mut-invalid':391 'mut-update-cach':397 'mut-usemut':380 'mutat':18,207,247,377,396,424,722,729,1089 'mutationfn':698,754 'name':885,936,980,984,986,1006 'need':137 'never':146,902 'new':135,490 'newpost':701 'non':161 'non-sensit':160 'note':51 'null':893,921,933 'number':568,582,589,629,819,884 'onclick':860,863 'onerror':107,389,710,783 'onmut':756 'onsettl':108,795 'onsubmit':733 'onsuccess':106,388,700 'opt':255,409,415,421 'opt-bas':408 'opt-rollback':414 'opt-vari':420 'optim':77 'optimist':209,252,405,412,743,775,1102 'option':99 'organ':291 'outgo':760 'overview':1078 'p':1039 'p.id':1040 'pagin':1114 'parallel':459,461 'partial':156,952 'password':150 'pattern':8,56,170,238,263,285,309,323,333,449,479,807 'perform':960 'persist':144,147,158,336,337,877,903,918,941,1150 'placeholderdata':100 'pmnd.rs':1188 'poimandr':1187 'post':543,544,546,587,592,652,666,668,705,716,1022,1037 'post.id':671 'post.title':672 'postfilt':556,616 'postlist':649 'practic':87 'prefetch':366,367 'prefix':228 'prevent':965 'previous':768 'previouspost':771,782,794 'prioriti':224,225 'provid':54,278,1166 'purpos':1174 'queri':5,40,45,65,94,175,218,231,270,289,305,363,433,435,454,460,466,468,471,478,493,534,1009,1015,1065,1067,1070,1077,1083,1095,1109,1115,1121,1176 'querycli':276,484,489,491,522,530,694,750 'queryclient.cancelqueries':763 'queryclient.getquerydata':772 'queryclient.invalidatequeries':707,802 'queryclient.setquerydata':777,790 'queryclientprovid':514,528 'queryfn':622,635 'querykey':288,541,604,619,632,683,708,764,803 'querykeys.posts.all':550,562 'querykeys.posts.detail':633,765,773,778,791,804 'querykeys.posts.details':569 'querykeys.posts.list':620 'querykeys.posts.lists':557,709 'querykeys.users.all':583,590 'quick':91,266 're':968,974 're-rend':967,973 'react':4,39,174,217,230,269,432,434,477,1008,1014,1064,1076,1120,1175 'reactquerydevtool':518,531 'read':1045 'recip':1158 'refactor':80 'refer':92,136,193,267,1063 'refetch':704,761,799 'refetchonwindowfocus':510 'remov':109,120,129 'render':969,975 'request':462 'reset':824,845 'retri':508 'return':134,527,617,630,658,661,665,696,731,752,781,857,985,1003,1004 'rollback':416,417,787 'rq':234,274,281,287,293,302,474 'rq-enabl':301 'rq-loading-error':292 'rq-querykey':286 'rq-setup':273 'rq-usequeri':280 'rule':182,221,1047 'rules/rq-mutation-setup.md':1057 'rules/rq-optimistic-updates.md':1058 'rules/rq-prefetching.md':1062 'rules/rq-query-invalidation.md':1061 'rules/rq-query-keys.md':1056 'rules/rq-usequery.md':1055 'rules/zs-create-store.md':1059 'rules/zs-persist.md':1060 'run':641 'scroll':456 'secret':152 'secur':143 'selectedpost':1036 'selectedpostid':1030,1041 'selector':133,326,328,958,963,988 'selectpost':1031 'sensit':162 'server':172,202,911,1012 'server-sid':910 'set':373,830,834,840,846,919,926,931 'settl':801 'setup':275,279,480 'shallow':125 'side':22,214,912 'skill':1164 'skill-state-management' 'snapshot':767 'source-asyrafhussin' 'stale':347,350 'staletim':494 'start':1139 'state':2,10,23,34,36,84,163,173,178,188,203,300,338,835,841,953,982,994,999,1013,1025,1028 'state-manag':1 'state.count':837,843 'state.isauthenticated':957,1000 'state.user':955,983,995 'still':112 'storag':340,939 'store':31,215,237,308,314,317,322,809,865,1151 'stores/useauthstore.ts':871 'stores/usecounterstore.ts':811 'strategi':446 'string':886,888 'suspens':116 'tanstack':44,64,93,1066,1069,1181 'tanstack.com':1073,1080,1086,1092,1099,1105,1111,1117,1124 'tanstack.com/query/latest)':1072 'tanstack.com/query/latest/docs/react/devtools)':1123 'tanstack.com/query/latest/docs/react/guides/infinite-queries)':1110 'tanstack.com/query/latest/docs/react/guides/mutations)':1091 'tanstack.com/query/latest/docs/react/guides/optimistic-updates)':1104 'tanstack.com/query/latest/docs/react/guides/paginated-queries)':1116 'tanstack.com/query/latest/docs/react/guides/queries)':1085 'tanstack.com/query/latest/docs/react/guides/query-keys)':1098 'tanstack.com/query/latest/docs/react/overview)':1079 'tanstack/react-query':486,516,602,681 'tanstack/react-query-devtools':520 'task':26 'time':348,351,355 'togeth':1034 'token':149,165,904,947 'topic-agent-rules' 'topic-agent-skills' 'topic-ai-agents' 'topic-ai-slop' 'topic-claude-code' 'topic-code-quality' 'topic-code-review' 'topic-codex' 'topic-cursor' 'topic-laravel' 'topic-nodejs' 'topic-react' 'trigger':24 'true':117,929 'tsx':481,537,597,675,745,810,870,961,1011 'typescript':320,321,867,1144 'ui':1027 'unnecessari':966 'updat':210,248,253,378,399,403,406,413,744,776,1103 'updatedpost':758,780,785 'updatedpost.id':766,774,779,792 'updatepost':755 'usag':645,718,849 'use':12,121,155,423,907,962,1033,1044 'useauthstor':915,981,993,998 'usecounterstor':828,856 'usecreatepost':692,724 'usemut':29,115,382,384,673,678,697,753 'usepost':614,627,655,1023 'usequeri':28,111,119,282,284,595,600,618,631 'usequerycli':679,695,751 'user':574,575,577,882,891,892,897,898,920,925,927,932,954,992,1005 'user.name':977 'userid':588,591 'userinfo':990 'usernam':971 'useshallow':130,138 'usesuspensequeri':122 'useuistor':1032 'useupdatepost':748 'v5':46,48,66,69,75,88,95,124 'valid':113 'valu':769 'variabl':422,425,798 'variables.id':805 'verifi':73 'version':42 'via':166 'void':821,823,825,899,901 'work':62 'zs':240,312,319,325,330,335 'zs-action':329 'zs-create-stor':311 'zs-persist':334 'zs-selector':324 'zs-typescript':318 'zustand':7,30,41,47,68,123,179,220,236,307,439,440,472,476,806,815,875,1010,1026,1126,1128,1132,1157,1182 'zustand-demo.pmnd.rs':1130 'zustand/middleware':880 'zustand/shallow':132","prices":[{"id":"85e87736-f57f-41a6-aa85-8c188fd2ab99","listingId":"38d41dc8-8dc3-43ba-960f-512b9fe26547","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"AsyrafHussin","category":"agent-skills","install_from":"skills.sh"},"createdAt":"2026-05-16T18:57:15.058Z"}],"sources":[{"listingId":"38d41dc8-8dc3-43ba-960f-512b9fe26547","source":"github","sourceId":"AsyrafHussin/agent-skills/state-management","sourceUrl":"https://github.com/AsyrafHussin/agent-skills/tree/main/skills/state-management","isPrimary":false,"firstSeenAt":"2026-05-16T18:57:15.058Z","lastSeenAt":"2026-05-18T18:58:25.424Z"}],"details":{"listingId":"38d41dc8-8dc3-43ba-960f-512b9fe26547","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"AsyrafHussin","slug":"state-management","github":{"repo":"AsyrafHussin/agent-skills","stars":39,"topics":["agent-rules","agent-skills","ai-agents","ai-slop","claude-code","code-quality","code-review","codex","cursor","laravel","nodejs","react","technical-debt","typescript","windsurf"],"license":"mit","html_url":"https://github.com/AsyrafHussin/agent-skills","pushed_at":"2026-05-16T19:24:02Z","description":"Agent skills for AI coding agents (Claude Code, Cursor, Codex, Windsurf) — Laravel, React, TypeScript, MySQL, code quality, technical debt, documentation, and security.","skill_md_sha":"0cfeb031fbfb985261252596525ad99d0ad0e9fa","skill_md_path":"skills/state-management/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/AsyrafHussin/agent-skills/tree/main/skills/state-management"},"layout":"multi","source":"github","category":"agent-skills","frontmatter":{"name":"state-management","license":"MIT","description":"React Query and Zustand patterns for state management. Use when implementing data fetching, caching, mutations, or client-side state. Triggers on tasks involving useQuery, useMutation, Zustand stores, caching, or state management."},"skills_sh_url":"https://skills.sh/AsyrafHussin/agent-skills/state-management"},"updatedAt":"2026-05-18T18:58:25.424Z"}}