Back to list
MUmerRazzaq

client-state-management

by MUmerRazzaq

0🍴 0📅 Dec 25, 2025

SKILL.md


name: client-state-management description: Guide for implementing client-side state management in React applications. Use when building state architecture, selecting state libraries (Context, Zustand, Redux, Jotai), implementing caching strategies (React Query, SWR), optimistic updates, state persistence, or optimizing re-renders. Triggers on questions about global vs local state, state normalization, or selector patterns.

Client-Side State Management

Decision: Library Selection

NeedUseWhy
Simple shared state, <5 consumersContext APIZero dependencies, built-in
Medium complexity, performance mattersZustand1.5kb, no boilerplate, auto re-render optimization
Large app, strict patterns neededRedux ToolkitDevTools, middleware ecosystem, time-travel
Fine-grained reactivity, atomsJotaiBottom-up, minimal re-renders, composable
Server state (fetching/caching)React Query or SWRDeduplication, background refresh, cache

Decision: Global vs Local State

Keep Local (useState/useReducer):

  • Form input values before submission
  • UI state (open/closed, hover, focus)
  • Component-specific loading/error states

Promote to Global:

  • User session/auth
  • Theme/locale preferences
  • Data shared across 3+ unrelated components
  • State that must survive navigation

State Normalization

Flatten nested data to avoid update complexity:

// Bad: nested
{ posts: [{ id: 1, author: { id: 1, name: 'Jo' }, comments: [...] }] }

// Good: normalized
{
  posts: { byId: { 1: { id: 1, authorId: 1, commentIds: [1,2] } }, allIds: [1] },
  users: { byId: { 1: { id: 1, name: 'Jo' } } },
  comments: { byId: { 1: {...}, 2: {...} } }
}

Optimistic Updates Pattern

Update UI immediately, rollback on error:

// React Query
useMutation({
  mutationFn: updateTodo,
  onMutate: async (newTodo) => {
    await queryClient.cancelQueries({ queryKey: ['todos'] })
    const previous = queryClient.getQueryData(['todos'])
    queryClient.setQueryData(['todos'], old => [...old, newTodo])
    return { previous }
  },
  onError: (err, newTodo, context) => {
    queryClient.setQueryData(['todos'], context.previous)
  },
  onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] })
})

State Persistence

// Zustand with persist middleware
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

const useStore = create(
  persist(
    (set) => ({ theme: 'light', setTheme: (t) => set({ theme: t }) }),
    {
      name: 'app-settings',
      storage: createJSONStorage(() => localStorage), // or sessionStorage
      partialize: (state) => ({ theme: state.theme }) // persist only specific keys
    }
  )
)

Performance: Selector Patterns

Prevent unnecessary re-renders by selecting only needed state:

// Zustand - component only re-renders when `count` changes
const count = useStore((state) => state.count)

// Jotai - selectAtom for derived slices
const nameAtom = selectAtom(userAtom, (user) => user.name)

// React Query - select option
useQuery({
  queryKey: ['user'],
  queryFn: fetchUser,
  select: (data) => data.name // component only gets name
})

Reference Files

Performance Checklist

  • Selectors return minimal data needed
  • Memoize selectors with expensive computations
  • Split stores by domain (don't put everything in one store)
  • Use shallow comparison for object selections in Zustand
  • Set appropriate staleTime/cacheTime for server state
  • Avoid storing derived state (compute from source)

Score

Total Score

50/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon