react

Applies to: React 18+, TypeScript, Single Page Applications, Component Libraries, Web Apps

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "react" with this command: npx skills add ar4mirez/samuel/ar4mirez-samuel-react

React Guide

Applies to: React 18+, TypeScript, Single Page Applications, Component Libraries, Web Apps

Core Principles

  • Component-Based: Build encapsulated components that manage their own state

  • Declarative: Describe what UI should look like, React handles DOM updates

  • Unidirectional Data Flow: Props down, callbacks up

  • Composition Over Inheritance: Prefer component composition and custom hooks

  • TypeScript First: All components use TypeScript with strict prop interfaces

Guardrails

Component Rules

  • Use functional components exclusively (no class components)

  • Keep components under 200 lines (split into smaller components)

  • Every component has a TypeScript interface for props

  • Use React.ReactNode for children props, not JSX.Element

  • Implement error boundaries for graceful error handling

  • Use proper accessibility attributes (ARIA roles, labels, keyboard navigation)

  • Co-locate component, styles, and tests in the same directory

Hooks Rules

  • Only call hooks at the top level (never inside conditions, loops, or nested functions)

  • Only call hooks from React function components or custom hooks

  • Name custom hooks with use prefix: useAuth , useQuery , useFetch

  • Always include all dependencies in useEffect / useMemo / useCallback arrays

  • Clean up side effects in useEffect return function

  • Prefer useReducer over useState for complex state logic

  • Use ESLint react-hooks plugin to enforce rules

State Management

  • Local state: useState for simple, useReducer for complex

  • Shared state: Context API for low-frequency updates (theme, auth, locale)

  • Server state: TanStack Query (React Query) for data fetching and caching

  • Global client state: Zustand for complex cross-component state

  • Avoid prop drilling beyond 2 levels (use composition or context)

  • Never store derived state (compute it during render)

Performance

  • Use React.memo() only for expensive pure components (measure first)

  • Use useMemo for expensive computations, useCallback for stable references

  • Lazy load routes and heavy components with React.lazy()

  • Suspense
  • Virtualize long lists (react-window, @tanstack/virtual)

  • Keep bundle under 200KB initial load (code-split aggressively)

  • Avoid anonymous functions in JSX for frequently re-rendered components

File Naming

  • Components: PascalCase.tsx (e.g., UserCard.tsx )

  • Hooks: camelCase.ts with use prefix (e.g., useAuth.ts )

  • Utils: camelCase.ts (e.g., formatDate.ts )

  • Types: camelCase.ts or types.ts per feature

  • Tests: *.test.tsx or *.spec.tsx (co-located)

  • Styles: *.module.css or *.styles.ts (co-located)

Project Structure

my-app/ ├── public/ │ └── index.html ├── src/ │ ├── assets/ # Static assets (images, fonts) │ ├── components/ # Reusable components │ │ ├── ui/ # Base UI components (Button, Input, Modal) │ │ └── features/ # Feature-specific components │ ├── hooks/ # Custom hooks │ ├── contexts/ # React contexts │ ├── services/ # API services │ ├── utils/ # Utility functions │ ├── types/ # TypeScript types │ ├── pages/ # Page components (route-level) │ ├── App.tsx │ ├── main.tsx │ └── index.css ├── tests/ ├── package.json ├── tsconfig.json ├── vite.config.ts └── README.md

  • components/ui/ for reusable design system primitives

  • components/features/ for domain-specific compositions

  • hooks/ for shared custom hooks (feature-specific hooks co-locate with component)

  • contexts/ for React context providers

  • services/ for API layer (fetch wrappers, API clients)

  • pages/ for route-level components only

Component Patterns

Functional Component with Props

interface UserCardProps { userId: string; onSelect?: (user: User) => void; className?: string; }

export function UserCard({ userId, onSelect, className }: UserCardProps) { const [user, setUser] = useState<User | null>(null); const [loading, setLoading] = useState(true);

useEffect(() => { const fetchUser = async () => { try { const data = await userService.getById(userId); setUser(data); } finally { setLoading(false); } }; fetchUser(); }, [userId]);

if (loading) return <Skeleton />; if (!user) return null;

return ( <div className={cn('user-card', className)} onClick={() => onSelect?.(user)}> <Avatar src={user.avatar} alt={user.name} /> <h3>{user.name}</h3> <p>{user.email}</p> </div> ); }

Component with Children

interface CardProps { title: string; children: React.ReactNode; footer?: React.ReactNode; }

export function Card({ title, children, footer }: CardProps) { return ( <div className="card"> <div className="card-header"><h2>{title}</h2></div> <div className="card-body">{children}</div> {footer && <div className="card-footer">{footer}</div>} </div> ); }

State Management Patterns

Context API (Auth, Theme, Locale)

interface AuthContextValue { user: User | null; login: (credentials: LoginCredentials) => Promise<void>; logout: () => void; isAuthenticated: boolean; }

const AuthContext = createContext<AuthContextValue | null>(null);

export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState<User | null>(null);

const login = async (credentials: LoginCredentials) => { const user = await authService.login(credentials); setUser(user); };

const logout = () => { authService.logout(); setUser(null); };

return ( <AuthContext.Provider value={{ user, login, logout, isAuthenticated: !!user }}> {children} </AuthContext.Provider> ); }

export function useAuth() { const context = useContext(AuthContext); if (!context) throw new Error('useAuth must be used within AuthProvider'); return context; }

TanStack Query (Server State)

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

function useUsers() { return useQuery({ queryKey: ['users'], queryFn: () => userService.getAll(), staleTime: 5 * 60 * 1000, }); }

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

Zustand (Complex Client State)

import { create } from 'zustand';

interface CartStore { items: CartItem[]; addItem: (item: CartItem) => void; removeItem: (id: string) => void; clearCart: () => void; total: () => number; }

const useCartStore = create<CartStore>()((set, get) => ({ items: [], addItem: (item) => set((state) => ({ items: [...state.items, item] })), removeItem: (id) => set((state) => ({ items: state.items.filter((item) => item.id !== id), })), clearCart: () => set({ items: [] }), total: () => get().items.reduce((sum, item) => sum + item.price * item.quantity, 0), }));

Routing (React Router v6)

import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import { lazy, Suspense } from 'react';

const Dashboard = lazy(() => import('./pages/Dashboard')); const Settings = lazy(() => import('./pages/Settings'));

const router = createBrowserRouter([ { path: '/', element: <Layout />, children: [ { index: true, element: <Home /> }, { path: 'dashboard', element: <Dashboard /> }, { path: 'settings', element: <Settings /> }, { path: '*', element: <NotFound /> }, ], }, ]);

function App() { return ( <Suspense fallback={<LoadingSpinner />}> <RouterProvider router={router} /> </Suspense> ); }

Forms (React Hook Form + Zod)

import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod';

const userSchema = z.object({ email: z.string().email('Invalid email'), password: z.string().min(8, 'Password must be at least 8 characters'), name: z.string().min(2, 'Name is required'), });

type UserFormData = z.infer<typeof userSchema>;

function UserForm({ onSubmit }: { onSubmit: (data: UserFormData) => void }) { const { register, handleSubmit, formState: { errors, isSubmitting }, reset, } = useForm<UserFormData>({ resolver: zodResolver(userSchema) });

const handleFormSubmit = async (data: UserFormData) => { await onSubmit(data); reset(); };

return ( <form onSubmit={handleSubmit(handleFormSubmit)}> <div> <label htmlFor="email">Email</label> <input id="email" type="email" {...register('email')} /> {errors.email && <span className="error">{errors.email.message}</span>} </div> <button type="submit" disabled={isSubmitting}> {isSubmitting ? 'Submitting...' : 'Submit'} </button> </form> ); }

Testing Overview

Standards

  • Use React Testing Library (@testing-library/react ) for component tests

  • Use userEvent over fireEvent for realistic user interactions

  • Test behavior, not implementation details

  • Query by accessible roles and labels first (not test IDs)

  • Mock API calls, not internal component state

  • Coverage target: >80% for business logic components

Basic Component Test

import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event';

describe('UserCard', () => { it('renders user information', () => { render(<UserCard user={mockUser} />); expect(screen.getByText('John Doe')).toBeInTheDocument(); });

it('calls onSelect when clicked', async () => { const onSelect = vi.fn(); render(<UserCard user={mockUser} onSelect={onSelect} />); await userEvent.click(screen.getByRole('button')); expect(onSelect).toHaveBeenCalledWith(mockUser); }); });

Tooling

Essential Commands

npm create vite@latest my-app -- --template react-ts # New project npm install # Install deps npm run dev # Dev server npm run build # Production build npm run lint # ESLint npm test # Run tests npm run test:cov # Coverage

Recommended Dependencies

{ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.x", "@tanstack/react-query": "^5.x", "zustand": "^4.x", "react-hook-form": "^7.x", "zod": "^3.x", "@hookform/resolvers": "^3.x" }, "devDependencies": { "@types/react": "^18.x", "@types/react-dom": "^18.x", "@testing-library/react": "^14.x", "@testing-library/user-event": "^14.x", "vitest": "^1.x", "eslint-plugin-react-hooks": "^4.x" } }

ESLint Configuration

{ "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react/recommended", "plugin:react-hooks/recommended" ], "rules": { "react/react-in-jsx-scope": "off", "react/prop-types": "off", "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn" } }

Advanced Topics

For detailed patterns and examples, see:

  • references/patterns.md -- Compound components, custom hooks, testing, performance, security patterns

External References

  • React Documentation

  • React TypeScript Cheatsheet

  • TanStack Query

  • Zustand

  • React Testing Library

  • React Hook Form

  • Zod

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

code-review

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

python-guide

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

typescript-guide

No summary provided by upstream source.

Repository SourceNeeds Review
General

actix-web

No summary provided by upstream source.

Repository SourceNeeds Review