Skip to main content
rule

react-zustand-cursorrules-prompt-file — Cursor rule: install and use

Cursor guidance for React and TypeScript projects using Zustand. It standardizes store design, stops unnecessary re-renders, and keeps server state separate from client stores.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/react-zustand-cursorrules-prompt-file.mdc
Open on GitHub

What react-zustand-cursorrules-prompt-file does

This rule guides Cursor when editing **/*.ts and **/*.tsx files with Zustand. It establishes clear boundaries for state management. Server responses stay inside data-fetching tools like TanStack Query or SWR, while transient form inputs remain in local component state. Only shared client data belongs in a Zustand store.

Store architecture focuses on state paired with explicit actions. Components must subscribe to fine-grained values or rely on useShallow rather than consuming entire store instances. Every action and slice requires explicit TypeScript types without any. Complex status workflows must use discriminated unions instead of loose booleans.

Because storing tokens or sensitive personal details in persist is forbidden, authorization state stays outside unencrypted browser storage. The rule also blocks React Server Components from touching browser stores, which prevents hydration mismatches.

What it helps with

  • separate server cache from shared client state without duplication
  • prevent redundant component re-renders using useShallow selectors
  • enforce strict TypeScript types for store actions without any
  • block sensitive tokens and credentials from browser persistence

Example prompts for the agent

  • Create a sidebar store with explicit toggle and panel selection actions
  • Add persist middleware for user interface preferences with a version migration
  • Write unit tests for the cart store actions directly without React components

How to install react-zustand-cursorrules-prompt-file

Manually: put the files in place

.cursor/rules/react-zustand-cursorrules-prompt-file.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about react-zustand-cursorrules-prompt-file

How to install react-zustand-cursorrules-prompt-file in Cursor?

Add the rule file to your project at .cursor/rules/react-zustand-cursorrules-prompt-file.mdc. It activates when working on .ts and .tsx files.

What does react-zustand-cursorrules-prompt-file do?

It directs Cursor to generate clean Zustand code, enforce shallow component subscriptions, and stop developers from turning global stores into monoliths.

Does the rule allow storing API data in Zustand?

No. It restricts Zustand to client-only state and instructs the agent to keep server data inside dedicated libraries like TanStack Query or RTK Query.

Source text

react-zustand-cursorrules-prompt-file.mdc · CC0-1.0
---
description: "React and TypeScript state management guidance for Zustand stores, selectors, middleware, persistence, and testing."
globs: **/*.ts, **/*.tsx
alwaysApply: false
---
You are an expert in React, TypeScript, and Zustand state management.

# React + Zustand Guidelines

## State Ownership
- Keep ephemeral UI state in the nearest component with `useState` or `useReducer`.
- Use URL state for shareable filters, pagination, tabs, and search params.
- Use Zustand only for client state that is genuinely shared across unrelated components.
- Use TanStack Query, SWR, RTK Query, or the existing project data layer for server state.
- Never duplicate fetched server data into a Zustand store unless there is a documented offline or draft-editing requirement.

## Store Design
- Model each store as state plus named actions; avoid exposing anonymous setters for component code to misuse.
- Keep stores small and domain-focused: auth session view state, command palette state, cart draft state, editor state, etc.
- Split large stores into typed slices, then apply middleware only at the composed store boundary.
- Keep derived values as selectors or small pure helpers unless they must be cached in state.
- Store serializable data by default; keep DOM nodes, promises, sockets, and timers outside store state.

```ts
import { create } from 'zustand'

interface SidebarState {
  isOpen: boolean
  activePanelId: string | null
}

interface SidebarActions {
  openPanel: (panelId: string) => void
  close: () => void
  toggle: () => void
}

type SidebarStore = SidebarState & SidebarActions

export const useSidebarStore = create<SidebarStore>()((set) => ({
  isOpen: false,
  activePanelId: null,
  openPanel: (panelId) => set({ isOpen: true, activePanelId: panelId }),
  close: () => set({ isOpen: false, activePanelId: null }),
  toggle: () => set((state) => ({ isOpen: !state.isOpen })),
}))
```

## Component Usage
- Subscribe to the smallest possible slice: `useStore((state) => state.value)`.
- Do not call a store hook without a selector in components unless the component truly needs every field.
- Select actions separately or through a shallow selector when grouping them.
- Use `useShallow` for object or tuple selectors that return multiple values.
- Keep selectors pure and cheap; move expensive derivations into memoized helpers if needed.

```tsx
import { useShallow } from 'zustand/react/shallow'
import { useSidebarStore } from '@/stores/sidebar-store'

export function SidebarToggle() {
  const { isOpen, toggle } = useSidebarStore(
    useShallow((state) => ({
      isOpen: state.isOpen,
      toggle: state.toggle,
    })),
  )

  return (
    <button type="button" aria-expanded={isOpen} onClick={toggle}>
      Toggle sidebar
    </button>
  )
}
```

## TypeScript
- Define explicit state and action interfaces for shared stores.
- Avoid `any`; use `unknown` plus narrowing for external data.
- Type action payloads and return values, including async actions.
- Prefer discriminated unions for complex local status instead of several loosely related booleans.
- Export store state types when tests, utilities, or vanilla store factories need them.

## Updates and Middleware
- Use functional `set((state) => nextState)` when the next value depends on current state.
- Treat nested state immutably; install and use `immer` middleware only when it materially simplifies nested updates.
- Use `persist` only for state that must survive reloads.
- Use `partialize`, `version`, and `migrate` when persisting anything beyond trivial preferences.
- Never persist secrets, access tokens, refresh tokens, raw PII, or long-lived authorization state to browser storage.
- Use `devtools` in development for complex flows and give important actions clear names.
- Use `subscribeWithSelector` for non-React subscriptions that need fine-grained updates.

## Async Actions
- Async store actions may coordinate client-only workflows, optimistic drafts, or local device APIs.
- Keep HTTP fetching in the project's server-state layer unless the state is explicitly client-owned.
- Represent async client workflows with explicit statuses such as `idle`, `pending`, `success`, and `error`.
- Reset error state deliberately when retrying or closing a workflow.

## SSR and React Server Components
- Do not read or mutate browser-only stores from React Server Components.
- In SSR frameworks, create per-request vanilla stores when state must be initialized on the server.
- Guard persisted stores against hydration mismatches before rendering storage-backed values.
- Keep store modules free of direct `window`, `document`, and storage access outside middleware configuration.

## Testing
- Test store actions directly without rendering React when possible.
- Reset stores between tests with their initial state.
- Assert selectors and actions separately from component behavior.
- Mock server-state libraries instead of routing fetched data through Zustand for tests.

## Anti-Patterns
- Do not create one global store for the entire application.
- Do not put form input state in Zustand unless multiple distant components edit the same draft.
- Do not mutate nested objects directly without Immer middleware.
- Do not use Zustand as an event bus; prefer explicit callbacks, services, or a scoped store.
- Do not introduce Redux-style reducers, action constants, or dispatch wrappers unless the project already uses that pattern.

© PatrickJS · CC0-1.0 · PatrickJS/awesome-cursorrules

Similar IDE rules

All IDE rules for Frontend and UI →

From the same set210

rtl-right-to-left-i18n-cursorrules-prompt-file A Cursor rule that pushes the agent toward logical CSS and Tailwind utilities instead of left/right. Useful when the app has to run in Arabic, Hebrew, Persian or Urdu. ★ 41,024repo stars ros-ros2 Enforces conventions for ROS and ROS2 workspaces, covering composable nodes, package layout, and launch testing. ★ 41,024repo stars readme-best-practices-cursorrules-prompt-file This rule guides an agent writing project READMEs, from the opening pitch to a runnable Quick Start. Use it when you want documentation readers can scan and try. ★ 41,024repo stars react This rule hands Cursor a set of React conventions: component structure, hooks, state, forms and accessibility. Useful when a project has plenty of .tsx and .jsx and you want one style. ★ 41,024repo stars react-typescript-symfony-cursorrules-prompt-file A Cursor rule that steers the assistant toward readable code across React, TypeScript, PHP, Symfony and Docker. ★ 41,024repo stars react-typescript-nextjs-nodejs-cursorrules-prompt- A Cursor rule that pins down React, TypeScript, Next.js 14 and Node.js conventions: functional components, RORO, minimal use client. ★ 41,024repo stars react-tanstack-router-query Guides AI assistants on structuring React SPAs with TanStack Router v1 and TanStack Query v5 to fetch data in loaders before rendering. ★ 41,024repo stars react-tanstack-router-query-cursorrules-prompt-file This rule describes a React SPA setup where TanStack Router handles navigation and TanStack Query stores server data. Use it to fetch route data before rendering a page. ★ 41,024repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor