Script Valley
React.js: Complete Course
State Management with Zustand and React QueryLesson 6.5

Combining Zustand and React Query in a real app

separation of concerns, server state in React Query, UI state in Zustand, derived state, avoiding duplication, real app architecture, devtools setup

Combining Zustand + React Query

The best practice: use React Query exclusively for server data (API responses), and Zustand for client/UI state (filters, selected items, modal state). Never put server data into Zustand — you lose caching, deduplication, and revalidation.

Example Architecture

// React Query — server state
const { data: products } = useQuery({
  queryKey: ['products', { category: selectedCategory }],
  queryFn: () => fetchProducts(selectedCategory),
});

// Zustand — UI/client state
const useUIStore = create((set) => ({
  selectedCategory: 'all',
  viewMode: 'grid',
  setCategory: (cat) => set({ selectedCategory: cat }),
  setViewMode: (mode) => set({ viewMode: mode }),
}));

function ProductsPage() {
  const { selectedCategory, viewMode, setCategory } = useUIStore();
  const { data: products, isLoading } = useQuery({
    queryKey: ['products', selectedCategory],
    queryFn: () => fetchProducts(selectedCategory),
  });

  return (
    <div>
      <CategoryFilter value={selectedCategory} onChange={setCategory} />
      {isLoading ? <Spinner /> : <ProductGrid items={products} mode={viewMode} />}
    </div>
  );
}

Install React Query DevTools in development to inspect cache state. Zustand's devtools middleware integrates with Redux DevTools. Both tools together give you full visibility into your app's state in development.