harness/plugins/zioinfo/skills/zio-harness/references/react.md
DESKTOP-TKLFCPR\ython 6caf43e1ed feat!: v2.0.0 — 4개 플러그인 zioinfo 단일 통합 + 최신 플러그인 기술 적용
- harness·zio-harness·proposal-builder·zioinfo → plugins/zioinfo (git mv 히스토리 보존)
- 스킬 4·커맨드 3(/zioinfo:pmo·proposal·wiki)·에이전트 15·graphify 훅·knowledge 통합
- 신규: /zioinfo:wiki (graphify LLM wiki — graphify-out/wiki/ 커뮤니티별 아티클)
- 신규: ZIO WISE 테마 (themes/zioinfo.json, experimental)
- manifest 최신화: $schema·displayName(ZIO INFOTECH Suite)·experimental.themes
- marketplace.json 단일 엔트리, 루트 plugin.json 제거
- CLAUDE.md·PROJECT_MAP·docs/plugins.md·README 3종·CHANGELOG·설치가이드 pptx 재구성

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 20:16:36 +09:00

3.6 KiB

React 개발 가이드

스택 가정

  • React 18+ + TypeScript
  • Vite 또는 Next.js
  • 상태 관리: Zustand (소규모) / Redux Toolkit (대규모)
  • 스타일: Tailwind CSS 또는 shadcn/ui
  • API 클라이언트: Axios + TanStack Query (서버 상태)

폴더 구조 원칙

src/
├── pages/          # 라우트 단위 페이지 (Next.js: app/ 또는 pages/)
├── components/
│   ├── ui/         # 재사용 원자 컴포넌트 (Button, Input, Modal)
│   └── features/   # 도메인별 조합 컴포넌트
├── hooks/          # 커스텀 훅 (use 접두사 필수)
├── store/          # Zustand store 또는 Redux slices
├── api/            # API 호출 함수 + TanStack Query hooks
├── types/          # 전역 TypeScript 타입
└── utils/          # 순수 유틸리티 함수

컴포넌트 작성 패턴

기본 구조

// src/components/features/UserCard.tsx
interface UserCardProps {
  userId: string;
  onSelect?: (id: string) => void;
}

export function UserCard({ userId, onSelect }: UserCardProps) {
  const { data: user } = useUser(userId);  // API 훅
  
  if (!user) return <Skeleton />;
  
  return (
    <div onClick={() => onSelect?.(userId)}>
      {user.name}
    </div>
  );
}

API 훅 패턴 (TanStack Query)

// src/api/users.ts
export function useUser(id: string) {
  return useQuery({
    queryKey: ['user', id],
    queryFn: () => api.get<User>(`/api/v1/users/${id}`),
  });
}

export function useCreateUser() {
  return useMutation({
    mutationFn: (data: CreateUserRequest) =>
      api.post<User>('/api/v1/users', data),
    onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
  });
}

Zustand Store 패턴

// src/store/authStore.ts
interface AuthState {
  user: User | null;
  token: string | null;
  setAuth: (user: User, token: string) => void;
  logout: () => void;
}

export const useAuthStore = create<AuthState>((set) => ({
  user: null,
  token: null,
  setAuth: (user, token) => set({ user, token }),
  logout: () => set({ user: null, token: null }),
}));

API 클라이언트 설정

// src/api/client.ts
const api = axios.create({
  baseURL: import.meta.env.VITE_API_URL,
  timeout: 10000,
});

api.interceptors.request.use((config) => {
  const token = useAuthStore.getState().token;
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

api.interceptors.response.use(
  (res) => res.data,
  (err) => {
    if (err.response?.status === 401) useAuthStore.getState().logout();
    return Promise.reject(err);
  }
);

라우팅 구조 (React Router v6)

// src/pages/Router.tsx
const router = createBrowserRouter([
  { path: '/', element: <Layout />, children: [
    { index: true, element: <Home /> },
    { path: 'users', element: <UserList /> },
    { path: 'users/:id', element: <UserDetail /> },
  ]},
  { path: '/login', element: <Login /> },
]);

환경 변수 패턴

# .env.local (git 제외)
VITE_API_URL=http://localhost:8080
VITE_APP_NAME=MyApp

TypeScript에서 타입 안전하게 접근:

// src/config.ts
export const config = {
  apiUrl: import.meta.env.VITE_API_URL,
  appName: import.meta.env.VITE_APP_NAME,
} as const;

컨벤션

항목 규칙 예시
컴포넌트 파일 PascalCase.tsx UserProfile.tsx
훅 파일 camelCase.ts, use 접두사 useAuth.ts
유틸 함수 camelCase.ts formatDate.ts
상수 UPPER_SNAKE_CASE MAX_RETRY_COUNT
인터페이스 PascalCase, I 접두사 없음 User, CreateUserRequest