← Back to all products
$29
State Management Patterns
Zustand, Jotai, and React Query patterns for complex state: optimistic updates, caching, and real-time sync.
JSONMarkdownTypeScriptReact
📄 Product Preview
Try the interactive reader and demo tools below, or get the full product with all content unlocked.
📖 Interactive Reader (Free Preview) ⚙ Try Demo Tools 📦 Download Free Sample📁 File Structure 25 files
state-management-patterns/
├── LICENSE
├── README.md
├── examples/
│ ├── dashboard-jotai.tsx
│ ├── data-table-react-query.tsx
│ └── todo-app-zustand.tsx
├── free-sample.zip
├── guide/
│ └── decision-guide.md
├── guides/
│ └── decision-guide.md
├── index.html
├── src/
│ ├── jotai/
│ │ ├── async-atoms.ts
│ │ ├── atom-families.ts
│ │ └── atoms.ts
│ ├── react-query/
│ │ ├── cache-invalidation.ts
│ │ ├── infinite-queries.ts
│ │ ├── mutations.ts
│ │ └── queries.ts
│ ├── realtime/
│ │ ├── optimistic-updates.ts
│ │ └── websocket-sync.ts
│ └── zustand/
│ ├── middleware.ts
│ ├── persistence.ts
│ └── store-slices.ts
├── tests/
│ ├── jotai.test.ts
│ ├── react-query.test.ts
│ └── zustand.test.ts
└── tsconfig.json
📖 Documentation Preview README excerpt
State Management Patterns
Battle-tested patterns for managing complex client state in React applications using Zustand, Jotai, and React Query. This collection covers the patterns that emerge when you move beyond simple useState — optimistic updates, cache synchronization, real-time data, and the hard decisions about where state actually belongs.
What's Inside
Zustand Patterns (`src/zustand/`)
- Store Slices — Split large stores into composable slices that share a single store instance. Includes typed slice creators and cross-slice communication.
- Middleware Stack — Logging, devtools integration, performance tracking, and immer middleware composed together.
- Persistence Layer — Storage adapters (localStorage, sessionStorage, IndexedDB) with migration support for evolving store shapes.
Jotai Patterns (`src/jotai/`)
- Atoms & Derived Atoms — Primitive atoms, computed atoms with selectors, and write-only atoms for complex updates.
- Async Atoms — Data fetching atoms with loading/error states, retry logic, and Suspense integration.
- Atom Families — Parameterized atoms for managing collections (e.g., per-item expanded state, per-tab filters).
React Query Patterns (`src/react-query/`)
- Query Patterns — Dependent queries, parallel queries, conditional fetching, and placeholder/initial data strategies.
- Mutations & Optimistic Updates — Mutation patterns with rollback, optimistic list updates, and toast notifications on failure.
- Infinite Queries — Cursor-based and offset-based infinite scroll with bi-directional support.
- Cache Invalidation — Granular invalidation, cache seeding from mutations, and stale-while-revalidate strategies.
Real-Time Sync (`src/realtime/`)
- WebSocket Integration — Reconnecting WebSocket manager that syncs server events into Zustand and React Query caches.
- Optimistic Updates — Shared patterns for optimistic UI across all three libraries, with server reconciliation.
Decision Guide (`guides/decision-guide.md`)
When should you reach for Zustand vs. Jotai vs. React Query? A decision tree based on the _shape_ of your state problem, not library popularity.
Working Examples (`examples/`)
- Todo app with Zustand (local-first with sync)
- Dashboard with Jotai (fine-grained reactivity)
- Data table with React Query (server state with filtering)
Quick Start
# Install the libraries you want to use (pick one or combine):
npm install zustand immer
npm install jotai
npm install @tanstack/react-query
# Copy the patterns you need into your project
cp -r src/zustand/ your-project/src/state/
Each pattern file is self-contained. Import what you need, ignore the rest.
File Structure
state-management-patterns/
├── README.md
├── LICENSE
├── tsconfig.json
├── src/
│ ├── zustand/
│ │ ├── store-slices.ts # Composable store slices
│ │ ├── middleware.ts # Custom middleware stack
│ │ └── persistence.ts # Storage adapters & migrations
*... continues with setup instructions, usage examples, and more.*
📄 Code Sample .ts preview
src/jotai/async-atoms.ts
// ============================================================================
// Jotai Async Atoms — Data Fetching with Loading & Error States
// ============================================================================
//
// Async atoms bridge the gap between server state and client state. They're
// Jotai's answer to the question: "Should I use React Query or can I handle
// data fetching with atoms?"
//
// The answer: use async atoms for data that's closely tied to other atom
// state (e.g., fetch products based on `selectedCategoryAtom`). Use React
// Query when you need built-in caching, background refetching, or pagination.
//
// Async atoms integrate with React Suspense, so your loading UI is handled
// at the boundary level rather than with `if (isLoading)` checks.
//
// ============================================================================
import { atom } from "jotai";
import { atomWithRefresh, loadable } from "jotai/utils";
import { selectedCategoryAtom, searchQueryAtom, sortOptionAtom } from "./atoms";
import type { Product, SortOption } from "./atoms";
// ---------------------------------------------------------------------------
// Mock API — replace with your real API client
// ---------------------------------------------------------------------------
const API_BASE = "https://api.example.com/v1";
interface PaginatedResponse<T> {
data: T[];
total: number;
page: number;
pageSize: number;
hasMore: boolean;
}
/**
* Simulate a network request with realistic delay and error rates.
* In your codebase, this would be `fetch()` or an Axios call.
*/
async function mockFetch<T>(
endpoint: string,
params: Record<string, string> = {},
options: { delay?: number; errorRate?: number } = {}
): Promise<T> {
const { delay = 300, errorRate = 0 } = options;
// Simulate network latency
await new Promise((resolve) => setTimeout(resolve, delay));
# ... 310 more lines ...