react-writing-code

Quick reference for writing production-quality React code. Each section summarizes the key rules — reference files provide full examples and edge cases.

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-writing-code" with this command: npx skills add ivantorresedge/molcajete.ai/ivantorresedge-molcajete-ai-react-writing-code

React Writing Code

Quick reference for writing production-quality React code. Each section summarizes the key rules — reference files provide full examples and edge cases.

React 19 Patterns

Server-First Model

Components are server components by default in frameworks that support them. Use "use client" only when the component needs browser APIs, hooks, or event handlers.

// Server Component — no directive needed async function DoctorList() { const doctors = await getDoctors(); return <ul>{doctors.map((d) => <DoctorCard key={d.id} doctor={d} />)}</ul>; }

// Client Component — needs interactivity "use client"; function BookButton({ doctorId }: { doctorId: string }) { const [isPending, setIsPending] = useState(false); return <button onClick={() => book(doctorId)}>Agendar</button>; }

Rules:

  • Keep client components small — push "use client" as far down the tree as possible

  • Server components can render client components, but not vice versa

  • Client components can accept server components as children

  • Never mark a component as "use client" just because a child is a client component

Form Actions

"use client"; import { useActionState } from "react";

function LoginForm() { const [state, formAction, isPending] = useActionState(loginAction, { error: null });

return ( <form action={formAction}> <input name="email" type="email" /> {state.error && <p className="text-destructive">{state.error}</p>} <button disabled={isPending}>{isPending ? "..." : "Iniciar sesión"}</button> </form> ); }

ref as a Prop (No forwardRef)

React 19 passes ref as a regular prop — forwardRef is no longer needed:

function Input({ ref, className, ...props }: InputProps & { ref?: React.Ref<HTMLInputElement> }) { return <input ref={ref} className={cn("...", className)} {...props} />; }

See references/react-19.md for use() hook, Suspense, error boundaries, optimistic updates, and metadata hoisting.

Component Composition

Prefer composition over configuration. Build components from smaller pieces rather than passing many props.

// ❌ Configuration-heavy <Card title="Dr. García" subtitle="Cardiología" badge="Disponible" footer={<BookButton />} />

// ✅ Composition <Card> <Card.Header> <Card.Title>Dr. García</Card.Title> <Badge>Disponible</Badge> </Card.Header> <Card.Footer><BookButton /></Card.Footer> </Card>

Key Patterns

Pattern Use When

Compound components Related components share implicit state (Tabs, Accordion, Dropdown)

Render props Consumer controls rendering, component controls logic

Polymorphic as prop Element type varies (Text as <p> , <span> , <label> )

Controlled + Uncontrolled Support both modes via optional value prop

Children as ReactNode Content is flexible (strings, elements, fragments)

Rules

  • Don't create components inside components — Inner components are re-created every render, resetting state

  • Don't use index as key — Causes bugs with reordering and deletion. Use stable unique IDs

  • Early returns over ternary chains — if (loading) return <Spinner /> is clearer than nested ternaries

See references/component-patterns.md for compound components, render props, polymorphic components, and controlled/uncontrolled patterns.

Custom Hooks

Extraction Rules

  • Two or more components need the same stateful logic → extract a hook

  • Three or more related state variables → extract a hook

  • Side effect needs cleanup (subscriptions, event listeners, timers) → extract a hook

  • Testability — logic needs testing independent of rendering → extract a hook

Key Principles

// Always prefix with use function useDebounce<T>(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const timer = setTimeout(() => setDebouncedValue(value), delay); return () => clearTimeout(timer); }, [value, delay]); return debouncedValue; }

  • Complete dependency arrays — Every value from component scope used in the effect must be listed

  • Always clean up — Return cleanup functions from useEffect for listeners, timers, abort controllers

  • Use refs for latest values — When you need current values in an effect without triggering re-runs

  • Don't call hooks conditionally — Always call at the top level

Common Anti-Pattern

// ❌ Wrong — useEffect for derived state const [filtered, setFiltered] = useState(items); useEffect(() => { setFiltered(items.filter((i) => i.name.includes(search))); }, [items, search]);

// ✅ Correct — compute during render const filtered = items.filter((i) => i.name.includes(search));

See references/hooks.md for cleanup patterns, useLocalStorage, useMediaQuery, useClickOutside, and anti-patterns.

State Management

Choose the Right Tool

State Type Tool Don't Use

Local UI (toggle, form input) useState

Zustand

Shared client state (auth, theme) Zustand Context for frequently changing values

Server data (API responses) urql Zustand — don't duplicate server state

URL-driven (search, pagination) React Router useSearchParams

Zustand or useState

Zustand Essentials

const useAuthStore = create<AuthState>((set) => ({ accessToken: null, user: null, setAuth: (accessToken, user) => set({ accessToken, user }), clearAuth: () => set({ accessToken: null, user: null }), }));

// ✅ Always use selectors — prevents unnecessary re-renders const user = useAuthStore((state) => state.user); const isAuthenticated = useAuthStore((state) => state.accessToken !== null);

// ❌ Never destructure the entire store const { user } = useAuthStore(); // Re-renders on ANY state change

urql for GraphQL

const [result] = useQuery({ query: VIEWER_QUERY });

if (result.fetching) return <Skeleton />; if (result.error) return <ErrorMessage error={result.error} />;

return <Profile user={result.data.viewer.me} />;

See references/state-management.md for Zustand middleware, slices, testing stores, urql auth exchange, and when NOT to use global state.

Performance

Measure First

Never optimize without profiling data. Use React DevTools Profiler to identify actual bottlenecks.

Optimization Techniques (In Order of Impact)

  • Code splitting — lazy()
  • Suspense at route boundaries. Biggest impact, lowest effort.
  • Avoid unnecessary renders — Fix the cause (unstable references, missing selectors) before reaching for memo .

  • React.memo — Only when profiling shows a component re-renders unnecessarily with the same props.

  • useMemo / useCallback — Stabilize expensive computations and callback references.

  • Virtualization — @tanstack/react-virtual for lists with 100+ items.

  • Debouncing — Delay expensive operations on rapid user input (search, resize).

Key Rules

// ✅ Route-based code splitting const Settings = lazy(() => import("./pages/Settings"));

// ✅ Stable callback reference (only when needed for memoized children) const handleDelete = useCallback((id: string) => { setItems((prev) => prev.filter((item) => item.id !== id)); }, []);

// ❌ Don't memoize everything "just in case" const MemoHeader = memo(Header); // Only if profiling proves it's needed

  • Don't create objects/arrays in render — Breaks memoization. Hoist constants or use useMemo .

  • Use urql for data fetching — Don't use useEffect

  • fetch . urql handles caching, races, and cleanup.
  • Debounce search input — 300ms delay prevents excessive API calls.

See references/performance.md for React.memo, code splitting, virtualization, image optimization, and profiling techniques.

Post-Change Verification

After every React code change, run the TypeScript verification protocol from the typescript-writing-code skill:

pnpm --filter <app> validate

or: pnpm run type-check && pnpm run lint && pnpm run format && pnpm run test

All 4 steps must pass. See typescript-writing-code skill for details.

Reference Files

File Description

references/react-19.md Server/client components, Actions, use() hook, Suspense, error boundaries

references/hooks.md Custom hooks, dependency management, cleanup patterns, common hooks

references/component-patterns.md Composition, compound components, render props, polymorphic, controlled/uncontrolled

references/state-management.md Zustand patterns, selectors, middleware, slices, urql, testing stores

references/performance.md React.memo, code splitting, lazy loading, virtualization, profiling

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

typescript-writing-code

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

typescript-testing

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

dev-workflow

No summary provided by upstream source.

Repository SourceNeeds Review