AgentSkillsCN

frontend-tanstack-store

当您需要创建或修改 TanStack Store 以实现全局状态管理时,可使用此技能。

SKILL.md
--- frontmatter
name: frontend-tanstack-store
description: Use when creating or modifying TanStack Store for global state management

Frontend: TanStack Store

Global state management using @tanstack/react-store with granular selectors.

When to Use

  • TanStack Store → Global app state (theme, user prefs, cross-page state)
  • Provider Context → Page/component-level state (see frontend-provider-context)
  • TanStack Query → Server state
  • useState → Single component state

Core Pattern

typescript
import { Store, useStore, shallow } from "@tanstack/react-store";

// 1. State class with defaults
class State_App {
    theme: "light" | "dark" = "light";
    sidebarCollapsed: boolean = false;
    notifications: string[] = [];
}

// 2. Store instance
export const Store_App = new Store(new State_App());

// 3. Selectors - one per key (granular subscriptions)
export const useStore_App_Theme = () => useStore(Store_App, (s) => s.theme);
export const useStore_App_SidebarCollapsed = () => useStore(Store_App, (s) => s.sidebarCollapsed);
export const useStore_App_Notifications = () =>
    useStore(Store_App, (s) => s.notifications, { equal: shallow });

// 4. Actions
export const Store_App_Actions = {
    overwrite: (partial: Partial<State_App>) => Store_App.setState((s) => ({ ...s, ...partial })),

    notifications: {
        add: (msg: string) =>
            Store_App.setState((s) => ({ ...s, notifications: [...s.notifications, msg] })),
        remove: (msg: string) =>
            Store_App.setState((s) => ({
                ...s,
                notifications: s.notifications.filter((n) => n !== msg),
            })),
        clear: () => Store_App.setState((s) => ({ ...s, notifications: [] })),
    },
};

Naming Conventions

EntityPatternExample
State classState_[Name]State_App, State_Editor
StoreStore_[Name]Store_App
Selector hookuseStore_[Name]_[Key]useStore_App_Theme
ActionsStore_[Name]_ActionsStore_App_Actions
FileStore_[Name].tssrc/stores/Store_App.ts

Usage

typescript
// Read (granular - only re-renders when this value changes)
const theme = useStore_App_Theme();
const notifications = useStore_App_Notifications();

// Write - simple values via overwrite
Store_App_Actions.overwrite({ theme: "dark" });
Store_App_Actions.overwrite({ theme: "dark", sidebarCollapsed: true });

// Write - complex operations via nested handlers
Store_App_Actions.notifications.add("New message");
Store_App_Actions.notifications.clear();

Selector Rules

State TypeSelector Pattern
PrimitivesuseStore(store, (s) => s.key)
Arrays/ObjectsuseStore(store, (s) => s.key, { equal: shallow })

MUST use shallow for arrays/objects to prevent re-renders when reference changes but contents are equal.

Action Rules

ScenarioUse
Simple value updatesoverwrite({ key: value })
Multiple keys at onceoverwrite({ key1: v1, key2: v2 })
Array mutationsNested handler: key.add(), key.remove(), key.clear()
Boolean toggleNested handler: key.toggle()
Computed updatesNested handler with logic

Nested handler naming:

TypeHandlers
Arraysadd, remove, clear, set
Booleanstoggle, set
Objectsupdate, set, clear

Anti-Patterns

WrongCorrect
useStore(store, (s) => s) (subscribe to all)useStore(store, (s) => s.specificKey)
Array selector without shallowuseStore(store, (s) => s.arr, { equal: shallow })
Direct Store.setState() in componentsUse Store_Actions.overwrite()
Nested state objectsKeep state flat
Individual setter per keyUse overwrite() for simple keys

Related Skills

  • frontend-provider-context - Page/component-level state (not global)
  • frontend-naming-conventions - General naming patterns
<!-- Last compacted: 2026-01-20 -->