CLAUDE.md@examples/claude-md/reactjs · git:20250901.24f54f2 · 2025-09-01 · sha256 b6c4fe9897c3c35b

CLAUDE.md@examples/claude-md/reactjs git:20250901.24f54f2A

Immutable. This exact content is served forever at /api/v1/blob/b6c4fe9897c3c35b.

# CLAUDE.md - React.js Project

This file provides guidance to Claude Code (claude.ai/code) when working with this React.js project.

## Project Architecture

This is a **React.js application** built with TypeScript, using modern React patterns and a component-based architecture.

### Project Structure
```
project/
├── public/                # Static assets
│   ├── index.html        # Main HTML template
│   └── favicon.ico       # Favicon
├── src/
│   ├── components/       # Reusable UI components
│   │   ├── ui/          # Base UI components (Button, Input, etc.)
│   │   ├── layout/      # Layout components (Header, Footer, Sidebar)
│   │   └── features/    # Feature-specific components
│   ├── pages/           # Page components (route components)
│   ├── hooks/           # Custom React hooks
│   ├── store/           # State management (Zustand/Redux)
│   ├── services/        # API calls and external services
│   ├── utils/           # Utility functions
│   ├── types/           # TypeScript type definitions
│   ├── styles/          # Global styles and theme
│   ├── assets/          # Images, icons, fonts
│   ├── App.tsx          # Main application component
│   └── main.tsx         # Application entry point
├── tests/               # Test files
└── docs/               # Documentation
```

## Development Commands

### Package Management
```bash
# Install dependencies
npm install
# or
yarn install
# or
pnpm install

# Install specific package
npm install package-name
yarn add package-name
pnpm add package-name

# Install dev dependency
npm install -D package-name
yarn add -D package-name
pnpm add -D package-name
```

### Development Server
```bash
# Start development server
npm run dev
# or
yarn dev
# or
pnpm dev

# Start with specific port
npm run dev -- --port 3001
```

### Building and Production
```bash
# Build for production
npm run build
# or
yarn build
# or
pnpm build

# Preview production build
npm run preview
# or
yarn preview
# or
pnpm preview
```

### Testing
```bash
# Run tests
npm test
# or
npm run test
# or
yarn test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage

# Run end-to-end tests (if using Playwright/Cypress)
npm run test:e2e
```

### Code Quality
```bash
# Lint code
npm run lint
# or
yarn lint

# Fix linting issues
npm run lint:fix

# Format code
npm run format

# Type checking
npm run type-check
```

## Technology Stack

### Core Framework
- **React 18+**: Modern React with concurrent features
- **TypeScript**: Static type checking
- **Vite**: Fast build tool and dev server

### State Management
- **Zustand**: Lightweight state management
- **TanStack Query**: Server state management
- **React Context**: For global app state (theme, auth)

### Styling
- **Tailwind CSS**: Utility-first CSS framework
- **CSS Modules**: Component-scoped CSS (alternative)
- **styled-components**: CSS-in-JS (alternative)

### UI Components
- **Radix UI**: Unstyled, accessible components
- **shadcn/ui**: Pre-built components with Tailwind
- **Heroicons**: Beautiful hand-crafted SVG icons

### Development Tools
- **Vitest**: Unit testing framework
- **Testing Library**: React component testing utilities
- **Playwright**: End-to-end testing
- **ESLint**: JavaScript/TypeScript linter
- **Prettier**: Code formatter
- **Storybook**: Component development environment

## Component Patterns

### Functional Components with Hooks
```tsx
// src/components/UserProfile.tsx
import React from 'react';
import { useQuery } from '@tanstack/react-query';
import { userService } from '../services/userService';

interface UserProfileProps {
  userId: string;
  onEdit?: () => void;
}

export const UserProfile: React.FC<UserProfileProps> = ({ userId, onEdit }) => {
  const { data: user, isLoading, error } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => userService.getById(userId),
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error loading user</div>;
  if (!user) return <div>User not found</div>;

  return (
    <div className="bg-white rounded-lg shadow p-6">
      <div className="flex items-center justify-between">
        <h2 className="text-xl font-semibold">{user.name}</h2>
        {onEdit && (
          <button
            onClick={onEdit}
            className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
          >
            Edit
          </button>
        )}
      </div>
      <p className="text-gray-600">{user.email}</p>
    </div>
  );
};
```

### Custom Hooks
```tsx
// src/hooks/useLocalStorage.ts
import { useState, useEffect } from 'react';

export function useLocalStorage<T>(key: string, initialValue: T) {
  const [storedValue, setStoredValue] = useState<T>(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.warn(`Error reading localStorage key "${key}":`, error);
      return initialValue;
    }
  });

  const setValue = (value: T | ((val: T) => T)) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.warn(`Error setting localStorage key "${key}":`, error);
    }
  };

  return [storedValue, setValue] as const;
}
```

### State Management with Zustand
```tsx
// src/store/authStore.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface User {
  id: string;
  name: string;
  email: string;
}

interface AuthState {
  user: User | null;
  token: string | null;
  isAuthenticated: boolean;
  login: (user: User, token: string) => void;
  logout: () => void;
}

export const useAuthStore = create<AuthState>()(
  persist(
    (set) => ({
      user: null,
      token: null,
      isAuthenticated: false,
      login: (user, token) => set({
        user,
        token,
        isAuthenticated: true,
      }),
      logout: () => set({
        user: null,
        token: null,
        isAuthenticated: false,
      }),
    }),
    {
      name: 'auth-storage',
    }
  )
);
```

## Routing (React Router)

```tsx
// src/App.tsx
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Layout } from './components/layout/Layout';
import { HomePage } from './pages/HomePage';
import { UserPage } from './pages/UserPage';
import { LoginPage } from './pages/LoginPage';
import { ProtectedRoute } from './components/ProtectedRoute';

const queryClient = new QueryClient();

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <BrowserRouter>
        <Routes>
          <Route path="/login" element={<LoginPage />} />
          <Route path="/" element={<Layout />}>
            <Route index element={<HomePage />} />
            <Route
              path="/users/:id"
              element={
                <ProtectedRoute>
                  <UserPage />
                </ProtectedRoute>
              }
            />
            <Route path="*" element={<Navigate to="/" replace />} />
          </Route>
        </Routes>
      </BrowserRouter>
    </QueryClientProvider>
  );
}
```

## API Integration

### Service Layer
```tsx
// src/services/apiClient.ts
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000/api';

class ApiClient {
  private baseURL: string;

  constructor(baseURL: string) {
    this.baseURL = baseURL;
  }

  async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
    const url = `${this.baseURL}${endpoint}`;
    const token = localStorage.getItem('auth-token');

    const config: RequestInit = {
      headers: {
        'Content-Type': 'application/json',
        ...(token && { Authorization: `Bearer ${token}` }),
        ...options.headers,
      },
      ...options,
    };

    const response = await fetch(url, config);

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    return response.json();
  }

  get<T>(endpoint: string): Promise<T> {
    return this.request<T>(endpoint);
  }

  post<T>(endpoint: string, data: any): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'POST',
      body: JSON.stringify(data),
    });
  }

  put<T>(endpoint: string, data: any): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'PUT',
      body: JSON.stringify(data),
    });
  }

  delete<T>(endpoint: string): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'DELETE',
    });
  }
}

export const apiClient = new ApiClient(API_BASE_URL);
```

### Data Fetching with TanStack Query
```tsx
// src/services/userService.ts
import { apiClient } from './apiClient';

export interface User {
  id: string;
  name: string;
  email: string;
  avatar?: string;
}

export const userService = {
  getById: (id: string): Promise<User> =>
    apiClient.get(`/users/${id}`),

  getAll: (): Promise<User[]> =>
    apiClient.get('/users'),

  create: (userData: Omit<User, 'id'>): Promise<User> =>
    apiClient.post('/users', userData),

  update: (id: string, userData: Partial<User>): Promise<User> =>
    apiClient.put(`/users/${id}`, userData),

  delete: (id: string): Promise<void> =>
    apiClient.delete(`/users/${id}`),
};

// Usage in component
export const useUsers = () => {
  return useQuery({
    queryKey: ['users'],
    queryFn: userService.getAll,
  });
};

export const useCreateUser = () => {
  const queryClient = useQueryClient();
  
  return useMutation({
    mutationFn: userService.create,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['users'] });
    },
  });
};
```

## Environment Configuration

### Environment Variables
```bash
# .env.local
VITE_API_URL=http://localhost:3000/api
VITE_APP_NAME=My React App
VITE_ENABLE_ANALYTICS=false
```

### Configuration Management
```tsx
// src/config/env.ts
interface Config {
  apiUrl: string;
  appName: string;
  enableAnalytics: boolean;
}

export const config: Config = {
  apiUrl: import.meta.env.VITE_API_URL || 'http://localhost:3000/api',
  appName: import.meta.env.VITE_APP_NAME || 'React App',
  enableAnalytics: import.meta.env.VITE_ENABLE_ANALYTICS === 'true',
};
```

## Vite Configuration

```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@/components': path.resolve(__dirname, './src/components'),
      '@/hooks': path.resolve(__dirname, './src/hooks'),
      '@/services': path.resolve(__dirname, './src/services'),
      '@/utils': path.resolve(__dirname, './src/utils'),
    },
  },
  server: {
    port: 3000,
    proxy: {
      '/api': {
        target: 'http://localhost:8000',
        changeOrigin: true,
      },
    },
  },
});
```

## Package.json Scripts

```json
{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:coverage": "vitest --coverage",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "lint:fix": "eslint . --ext ts,tsx --fix",
    "format": "prettier --write .",
    "type-check": "tsc --noEmit",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  }
}
```