react

React Best Practices (2025)

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 lyq-lin/ycode.cli/lyq-lin-ycode-cli-react

React Best Practices (2025)

Component Patterns

Functional Components Only

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

function UserCard({ user, onSelect }: UserCardProps) { return ( <article onClick={() => onSelect?.(user)}> <h2>{user.name}</h2> </article> ); }

Props Destructuring

  • Always destructure props in function signature

  • Use default values: { size = 'md' }: Props

  • Spread remaining props: { className, ...rest }

Composition Over Props Drilling

// ❌ Prop drilling <Parent user={user}> <Child user={user}> <GrandChild user={user} /> </Child> </Parent>

// ✅ Composition <UserProvider user={user}> <Parent> <Child> <GrandChild /> </Child> </Parent> </UserProvider>

Page Patterns

Unified Create/Edit Form

Single form component handles both modes via optional entity prop:

interface EntityFormProps { entity?: Entity; onSuccess: (entity: Entity) => void; onCancel: () => void; }

function EntityForm({ entity, onSuccess, onCancel }: EntityFormProps) { const isEdit = Boolean(entity); const [formData, setFormData] = useState(entity ?? initialFormData);

// Conditional mutation based on mode // Edit-only features (delete, publish) render when isEdit }

Pages become thin wrappers:

// CreatePage <EntityForm onSuccess={(e) => navigate(/entities/${e.id})} onCancel={() => navigate('/entities')} />

// EditPage - fetch data first const { data: entity } = useEntity(id); <EntityForm entity={entity} onSuccess={...} onCancel={...} />

Reusable UI Components

Extract repeated patterns: Pagination , Snackbar , DeleteConfirmModal , StatusBadge

Hooks Best Practices

useState

  • Use functional updates for derived state: setCount(c => c + 1)

  • Prefer multiple states over one object

  • Initialize expensive state with function: useState(() => computeExpensive())

useEffect

  • One effect per concern

  • Always include cleanup when needed

  • Avoid objects in dependency arrays (use primitives)

// ✅ Good: Minimal dependencies useEffect(() => { const handler = () => setWidth(window.innerWidth); window.addEventListener("resize", handler); return () => window.removeEventListener("resize", handler); }, []); // Empty = mount only

useMemo / useCallback

  • Only for expensive computations

  • Only when passing to memoized children

  • Don't over-optimize prematurely

// Memoize expensive filter const filtered = useMemo( () => items.filter((i) => i.name.includes(search)), [items, search], );

// Memoize callback for React.memo child const handleClick = useCallback((id: string) => setSelected(id), []);

Custom Hooks

  • Extract reusable logic

  • Name with use prefix

  • Return tuple or object consistently

function useLocalStorage<T>(key: string, initial: T) { const [value, setValue] = useState<T>(() => { const stored = localStorage.getItem(key); return stored ? JSON.parse(stored) : initial; });

useEffect(() => { localStorage.setItem(key, JSON.stringify(value)); }, [key, value]);

return [value, setValue] as const; }

State Management

Hierarchy (prefer top to bottom)

  • Local state - Component-specific

  • Lifted state - Shared between siblings

  • Context - Cross-cutting (theme, auth)

  • External store - Complex global state (Zustand, Jotai)

When to Use Context

  • Theme/appearance

  • User authentication

  • Locale/i18n

  • Feature flags

Zustand Pattern (Recommended)

const useStore = create<State>((set) => ({ items: [], addItem: (item) => set((s) => ({ items: [...s.items, item] })), removeItem: (id) => set((s) => ({ items: s.items.filter((i) => i.id !== id), })), }));

TypeScript Patterns

Props Types

interface Props { required: string; optional?: number; children: React.ReactNode; onClick: (event: React.MouseEvent) => void; as?: React.ElementType; }

Generic Components

interface ListProps<T> { items: T[]; renderItem: (item: T) => React.ReactNode; keyExtractor: (item: T) => string; }

function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) { return ( <ul> {items.map((item) => ( <li key={keyExtractor(item)}>{renderItem(item)}</li> ))} </ul> ); }

Performance

React.memo

  • Wrap components receiving same props repeatedly

  • Combine with useCallback for function props

  • Don't use everywhere (adds overhead)

Lazy Loading

const HeavyComponent = lazy(() => import("./HeavyComponent"));

function App() { return ( <Suspense fallback={<Spinner />}> <HeavyComponent /> </Suspense> ); }

Keys

  • Use stable, unique IDs (not array index)

  • Changing key forces remount

Testing (Vitest + Testing Library)

import { render, screen, fireEvent } from "@testing-library/react";

describe("Button", () => { it("calls onClick when clicked", () => { const handleClick = vi.fn(); render(<Button onClick={handleClick}>Click</Button>);

fireEvent.click(screen.getByRole("button"));

expect(handleClick).toHaveBeenCalledOnce();

}); });

Common Mistakes

❌ Avoid:

  • Mutating state directly

  • Async operations in render

  • Inline object/array creation in JSX (causes re-renders)

  • Missing keys in lists

  • useEffect without dependencies

  • Over-abstracting too early

✅ Do:

  • Treat state as immutable

  • Use error boundaries

  • Colocate state with usage

  • Memoize expensive computations

  • Use TypeScript strictly

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

ant-design-knowledge-base

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

frontend-design

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

ui-ux-pro-max

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

code-review

No summary provided by upstream source.

Repository SourceNeeds Review