npx skillsauth add excatt/superclaude-plusplus stateInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
상태 관리 패턴 가이드를 실행합니다.
Local State 컴포넌트 내부 (useState)
Shared State 여러 컴포넌트 공유 (Zustand, Jotai)
Server State 서버 데이터 (TanStack Query, SWR)
URL State URL 파라미터 (Router)
Form State 폼 데이터 (React Hook Form)
| 상태 유형 | 2024 권장 도구 | |----------|---------------| | 단순 로컬 | useState | | 복잡한 로컬 | useReducer | | 전역 클라이언트 | Zustand (1순위), Jotai | | 서버 데이터 | TanStack Query (1순위) | | 폼 | React Hook Form + Zod | | URL | nuqs, next-usequerystate |
import { create } from 'zustand';
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 }),
}));
// 사용
function Counter() {
const { count, increment } = useCounterStore();
return <button onClick={increment}>{count}</button>;
}
// ❌ 전체 store 구독 (불필요한 리렌더)
const { count, user } = useCounterStore();
// ✅ 필요한 값만 구독
const count = useCounterStore((state) => state.count);
const user = useCounterStore((state) => state.user);
// ✅ 여러 값 선택 (shallow 비교)
import { useShallow } from 'zustand/react/shallow';
const { count, user } = useCounterStore(
useShallow((state) => ({ count: state.count, user: state.user }))
);
import { create } from 'zustand';
import { persist, devtools, subscribeWithSelector } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
interface UserStore {
user: User | null;
preferences: { theme: 'light' | 'dark' };
setUser: (user: User) => void;
updatePreferences: (prefs: Partial<UserStore['preferences']>) => void;
}
const useUserStore = create<UserStore>()(
devtools(
persist(
immer((set) => ({
user: null,
preferences: { theme: 'light' },
setUser: (user) => set({ user }),
updatePreferences: (prefs) =>
set((state) => {
Object.assign(state.preferences, prefs);
}),
})),
{
name: 'user-storage',
partialize: (state) => ({ preferences: state.preferences }), // 일부만 저장
}
),
{ name: 'UserStore' }
)
);
// stores/userSlice.ts
export interface UserSlice {
user: User | null;
setUser: (user: User) => void;
logout: () => void;
}
export const createUserSlice: StateCreator<UserSlice> = (set) => ({
user: null,
setUser: (user) => set({ user }),
logout: () => set({ user: null }),
});
// stores/cartSlice.ts
export interface CartSlice {
items: CartItem[];
addItem: (item: CartItem) => void;
removeItem: (id: string) => void;
}
export const createCartSlice: StateCreator<CartSlice> = (set) => ({
items: [],
addItem: (item) => set((state) => ({ items: [...state.items, item] })),
removeItem: (id) => set((state) => ({
items: state.items.filter((i) => i.id !== id)
})),
});
// stores/index.ts
type StoreState = UserSlice & CartSlice;
export const useStore = create<StoreState>()((...a) => ({
...createUserSlice(...a),
...createCartSlice(...a),
}));
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai';
// Primitive atom
const countAtom = atom(0);
// Derived atom (읽기 전용)
const doubleCountAtom = atom((get) => get(countAtom) * 2);
// Derived atom (읽기/쓰기)
const incrementAtom = atom(
null,
(get, set) => set(countAtom, get(countAtom) + 1)
);
// Async atom
const userAtom = atom(async () => {
const response = await fetch('/api/user');
return response.json();
});
// 사용
function Counter() {
const count = useAtomValue(countAtom); // 읽기만
const setCount = useSetAtom(countAtom); // 쓰기만
const [value, setValue] = useAtom(countAtom); // 둘 다
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
import { atomFamily } from 'jotai/utils';
const todoAtomFamily = atomFamily((id: string) =>
atom({
id,
text: '',
completed: false,
})
);
// 사용
function TodoItem({ id }: { id: string }) {
const [todo, setTodo] = useAtom(todoAtomFamily(id));
// ...
}
import { atomWithStorage } from 'jotai/utils';
const themeAtom = atomWithStorage('theme', 'light');
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
// 조회
function useUsers() {
return useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then((r) => r.json()),
staleTime: 5 * 60 * 1000, // 5분간 fresh
gcTime: 30 * 60 * 1000, // 30분 캐시 유지 (v5: cacheTime → gcTime)
});
}
// 상세 조회
function useUser(id: string) {
return useQuery({
queryKey: ['users', id],
queryFn: () => fetch(`/api/users/${id}`).then((r) => r.json()),
enabled: !!id, // id가 있을 때만 실행
});
}
function useCreateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (newUser: NewUser) =>
fetch('/api/users', {
method: 'POST',
body: JSON.stringify(newUser),
}).then((r) => r.json()),
// Optimistic update
onMutate: async (newUser) => {
await queryClient.cancelQueries({ queryKey: ['users'] });
const previous = queryClient.getQueryData(['users']);
queryClient.setQueryData(['users'], (old: User[]) => [
...old,
{ ...newUser, id: 'temp-id' },
]);
return { previous };
},
onError: (err, newUser, context) => {
queryClient.setQueryData(['users'], context?.previous);
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
},
});
}
function useInfiniteUsers() {
return useInfiniteQuery({
queryKey: ['users', 'infinite'],
queryFn: ({ pageParam }) =>
fetch(`/api/users?cursor=${pageParam}`).then((r) => r.json()),
initialPageParam: 0,
getNextPageParam: (lastPage) => lastPage.nextCursor,
});
}
// 사용
function UserList() {
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteUsers();
return (
<>
{data?.pages.map((page) =>
page.users.map((user) => <UserCard key={user.id} user={user} />)
)}
{hasNextPage && (
<button onClick={() => fetchNextPage()} disabled={isFetchingNextPage}>
{isFetchingNextPage ? 'Loading...' : 'Load More'}
</button>
)}
</>
);
}
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
email: z.string().email('유효한 이메일을 입력하세요'),
password: z.string().min(8, '8자 이상 입력하세요'),
confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
message: '비밀번호가 일치하지 않습니다',
path: ['confirmPassword'],
});
type FormData = z.infer<typeof schema>;
function SignupForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<FormData>({
resolver: zodResolver(schema),
});
const onSubmit = async (data: FormData) => {
await signup(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email')} />
{errors.email && <span>{errors.email.message}</span>}
<input type="password" {...register('password')} />
{errors.password && <span>{errors.password.message}</span>}
<input type="password" {...register('confirmPassword')} />
{errors.confirmPassword && <span>{errors.confirmPassword.message}</span>}
<button disabled={isSubmitting}>Sign Up</button>
</form>
);
}
import { useQueryState, parseAsInteger, parseAsString } from 'nuqs';
function ProductList() {
const [search, setSearch] = useQueryState('q', parseAsString.withDefault(''));
const [page, setPage] = useQueryState('page', parseAsInteger.withDefault(1));
const [sort, setSort] = useQueryState('sort', parseAsString.withDefault('newest'));
// URL: /products?q=shoes&page=2&sort=price
return (
<div>
<input value={search} onChange={(e) => setSearch(e.target.value)} />
<button onClick={() => setPage(page + 1)}>Next Page</button>
</div>
);
}
## State Management Design
### State Classification
| 상태 | 유형 | 도구 |
|------|------|------|
| 사용자 정보 | Server | TanStack Query |
| 테마 설정 | Global | Zustand (persist) |
| 검색 필터 | URL | nuqs |
| 로그인 폼 | Form | React Hook Form |
### Implementation
```typescript
// 상태 관리 코드
stores/
├── useUserStore.ts # Zustand
├── atoms/ # Jotai (선택)
│ └── themeAtom.ts
└── queries/ # TanStack Query
└── useUsers.ts
---
요청에 맞는 상태 관리 전략을 설계하세요.
testing
사용자 계획을 기존 도메인 모델에 대해 stress-test하는 인터뷰 세션. 용어를 날카롭게 다듬고, 결정이 굳어질 때마다 CONTEXT.md(도메인 어휘 사전)와 ADR을 인라인으로 갱신한다. 새 기능 요구사항 탐색은 `/brainstorm`을, 기존 도메인 모델·용어와의 정합성 점검은 이 스킬을 사용한다.
development
# Excel (XLSX) Spreadsheet Skill Claude Code supports comprehensive spreadsheet operations through the **xlsx** skill, enabling creation, editing, and analysis of Excel files (.xlsx, .xlsm, .csv, .tsv). ## Trigger - When user needs Excel spreadsheet creation or editing - Financial modeling or data analysis required - Spreadsheet formulas and calculations needed - Data import from CSV/TSV files ## Core Capabilities **Primary functions include:** - Creating new spreadsheets with formulas and f
tools
Generate structured implementation workflows from PRDs and feature requirements
development
실시간 통신 설계 가이드를 실행합니다.