用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/emanueleielo/deepagents-open-lovable --skill state-management命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | state-management |
| description | State management patterns - Zustand, Jotai, Context |
| State Type | Solution | Example |
|---|---|---|
| Server state | TanStack Query | API data, user profile |
| Form state | React Hook Form | Form inputs, validation |
| Local UI | useState | Modal open, input value |
| Shared UI | Zustand / Jotai | Theme, sidebar open, filters |
| Complex shared | Zustand | Shopping cart, multi-step wizard |
Rule: Server data belongs in TanStack Query, NOT in global state.
import { create } from "zustand";
import { persist } from "zustand/middleware";
// Basic store
interface CounterStore {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
}
const useCounterStore = create<CounterStore>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));
// Usage
function Counter() {
const { count, increment, decrement } = useCounterStore();
return (
<div>
<span>{count}</span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
// Select specific values (prevents re-renders)
function CountDisplay() {
const count = useCounterStore((state) => state.count);
return <span>{count}</span>;
}
import { create, StateCreator } from "zustand";
import { devtools, persist } from "zustand/middleware";
// User slice
interface UserSlice {
user: User | null;
setUser: (user: User | null) => void;
}
const createUserSlice: StateCreator<UserSlice> = (set) => ({
user: null,
setUser: (user) => set({ user }),
});
// Cart slice
interface CartSlice {
items: CartItem[];
addItem: (item: CartItem) => void;
removeItem: (id: string) => void;
clearCart: () => void;
total: () => number;
}
const : < & , [], [], > = ({
: [],
: ( ({
: [...state., item]
})),
: ( ({
: state..( i. !== id)
})),
: ({ : [] }),
: ()..( sum + item., ),
});
= & ;
useStore = create<>()(
(
(
({
...(...a),
...(...a),
}),
{ : }
)
)
);
import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
import { atomWithStorage } from "jotai/utils";
// Primitive atom
const countAtom = atom(0);
// Derived atom (read-only)
const doubleAtom = atom((get) => get(countAtom) * 2);
// Writable derived atom
const countWithMaxAtom = atom(
(get) => get(countAtom),
(get, set, newValue: number) => {
set(countAtom, Math.min(newValue, 100));
}
);
// Async atom
const userAtom = atom(async () => {
const res = await fetch("/api/user");
return res.json();
});
// Persisted atom
const themeAtom = atomWithStorage<"light" | "dark">("theme", "light");
// Usage
function Counter() {
[count, setCount] = (countAtom);
double = (doubleAtom);
(
);
}
() {
setCount = (countAtom);
;
}
import { atom } from "jotai";
import { atomFamily } from "jotai/utils";
// Atom family for per-item state
const itemQuantityAtomFamily = atomFamily((itemId: string) =>
atom(1)
);
// Usage
function ItemQuantity({ itemId }: { itemId: string }) {
const [quantity, setQuantity] = useAtom(itemQuantityAtomFamily(itemId));
return (
<div>
<button onClick={() => setQuantity((q) => Math.max(1, q - 1))}>-</button>
<span>{quantity}</span>
<button onClick={() => setQuantity((q) => q + 1)}>+</button>
</div>
);
}
Use Context for:
import { createContext, useContext, useState, ReactNode } from "react";
interface ThemeContextValue {
theme: "light" | "dark";
toggle: () => void;
}
const ThemeContext = createContext<ThemeContextValue | null>(null);
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) throw new Error("useTheme must be used within ThemeProvider");
return context;
}
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<"light" | "dark">("light");
const toggle = () => setTheme((t) => (t === "light" ? "dark" : "light"));
return (
<ThemeContext.Provider value= , }}>
{children}
);
}
// Store for UI state only
const useUIStore = create<UIStore>((set) => ({
sidebarOpen: true,
toggleSidebar: () => set((s) => ({ sidebarOpen: !s.sidebarOpen })),
// Filters affect query key
filters: { status: "all", search: "" },
setFilters: (filters) => set({ filters }),
}));
// Component
function UserList() {
const filters = useUIStore((s) => s.filters);
// Server state in Query, UI filters in Zustand
const { data: users } = useQuery({
queryKey: ["users", filters],
queryFn: () => fetchUsers(filters),
});
return (
<div>
<FilterBar />
{users?.map((user) => <UserCard key={user.id} user={user} />)}
);
}
| Feature | Zustand | Jotai | Context |
|---|---|---|---|
| Boilerplate | Low | Very low | Medium |
| DevTools | Yes | Yes | React DevTools |
| Persistence | Middleware | Built-in | Manual |
| Selectors | Built-in | Atoms | useMemo |
| Async | Manual | Built-in | Manual |
| Best for | Single store | Many atoms | DI, compound |