소스 정보
- 저장소
- emanueleielo/deepagents-open-lovable
- 최근 소스 활동
- 2026년 1월 10일 09:00
- 감지된 SKILL.md 언어
- 영어
- 스타
- 109
- 포크
- 25
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/emanueleielo/deepagents-open-lovable --skill state-management명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| 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 |