Use Cases (Actualizado: 2/6/2026)

React con Claude Code en producción: componentes, Hooks, tests y revisión

Usa Claude Code para desarrollar React con componentes tipados, Hooks, pruebas, accesibilidad y revisión segura.

React con Claude Code en producción: componentes, Hooks, tests y revisión

Claude Code puede acelerar mucho el desarrollo con React, pero en un equipo de producción la velocidad no basta. Lo importante es obtener cambios pequeños, revisables y comprobados. Si le pides “crea un dashboard bonito” sin límites, lo normal es terminar con demasiados componentes, demasiadas props y poca confianza.

Esta guía muestra un flujo práctico para React + TypeScript: límites de componentes, props, state, custom hooks, formularios, data fetching, pruebas con Testing Library, accesibilidad, rendimiento y prompts de revisión. Usa como base la documentación oficial de React, React Testing Library, MDN ARIA y Claude Code. Para seguir dentro de ClaudeCodeLab, revisa TypeScript tips, estrategias de testing, accesibilidad y optimización de rendimiento.

Define el contrato antes de generar

Props son entradas que un componente padre pasa a un hijo. State es lo que la interfaz recuerda. Un custom hook es una función reutilizable para lógica con estado o efectos. Un efecto incluye peticiones API, temporizadores o localStorage.

InformaciónEjemploResultado
Responsabilidadlistar usuarios, filtrar, activar cuentasevita componentes gigantes
Ubicación del estadopadre, URL, hook, cache de servidorevita useState disperso
Datostipo User, respuesta API, estado vacíoprops y tests concretos
Verificaciónnpm test, npm run build, tecladoevidencia para revisión

Casos de uso reales

Caso uno: listas internas de administración, como usuarios, facturas, tickets o permisos. Claude Code puede dividir filtros, tabla, acciones por fila, estado vacío y error sin cambiar el contrato API.

Caso dos: formularios de perfil, contacto, checkout o inscripción a formación. Pídele que respete labels, validación, estado de envío y reintentos. Para formularios más complejos, consulta React Hook Form con Claude Code.

Caso tres: pantallas con datos del servidor, como búsqueda, notificaciones y dashboards. Separa server state de state temporal de UI. Para TanStack Query, lee TanStack Query; para estado cliente pequeño, compara Zustand.

Caso cuatro: revisión de código. En vez de pedir más UI, pide revisar el diff: límites de componentes, efectos innecesarios, accesibilidad, tests frágiles y renders evitables.

Diagrama de componentes

UserAdminPage
  -> UserFilters: búsqueda y rol
  -> UserTable: tabla y acciones
  -> UserStatusBadge: solo estado visual
  -> UserEditDialog: formulario
  -> useUsers: fetch, refresh, error

Componente React tipado

Este ejemplo funciona en un proyecto Vite + React + TypeScript. No hace fetch; recibe datos y comunica eventos hacia arriba.

import type { FormEvent } from "react";

export type UserRole = "admin" | "editor" | "viewer";

export type User = {
  id: string;
  name: string;
  email: string;
  role: UserRole;
  active: boolean;
};

type UserTableProps = {
  users: User[];
  selectedRole: "all" | UserRole;
  onRoleChange: (role: "all" | UserRole) => void;
  onToggleActive: (id: string) => void;
};

export function UserTable({ users, selectedRole, onRoleChange, onToggleActive }: UserTableProps) {
  const filteredUsers = selectedRole === "all" ? users : users.filter((user) => user.role === selectedRole);

  function handleRoleSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    onRoleChange(formData.get("role") as "all" | UserRole);
  }

  return (
    <section aria-labelledby="user-table-title">
      <h2 id="user-table-title">Team members</h2>
      <form onSubmit={handleRoleSubmit} style={{ marginBottom: 12 }}>
        <label htmlFor="role">Filter by role </label>
        <select id="role" name="role" defaultValue={selectedRole}>
          <option value="all">All</option>
          <option value="admin">Admin</option>
          <option value="editor">Editor</option>
          <option value="viewer">Viewer</option>
        </select>
        <button type="submit">Apply</button>
      </form>
      {filteredUsers.length === 0 ? (
        <p role="status">No users match this filter.</p>
      ) : (
        <table>
          <thead>
            <tr>
              <th scope="col">Name</th>
              <th scope="col">Email</th>
              <th scope="col">Role</th>
              <th scope="col">Status</th>
              <th scope="col">Action</th>
            </tr>
          </thead>
          <tbody>
            {filteredUsers.map((user) => (
              <tr key={user.id}>
                <td>{user.name}</td>
                <td>{user.email}</td>
                <td>{user.role}</td>
                <td>{user.active ? "Active" : "Paused"}</td>
                <td>
                  <button type="button" onClick={() => onToggleActive(user.id)}>
                    {user.active ? "Pause" : "Activate"}
                  </button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
    </section>
  );
}

Hook y test

import { useEffect, useState } from "react";
import type { User } from "./UserTable";

type UsersState =
  | { status: "loading"; users: User[]; error: null }
  | { status: "success"; users: User[]; error: null }
  | { status: "error"; users: User[]; error: string };

export function useUsers(endpoint: string) {
  const [state, setState] = useState<UsersState>({ status: "loading", users: [], error: null });

  useEffect(() => {
    const controller = new AbortController();
    async function loadUsers() {
      setState({ status: "loading", users: [], error: null });
      try {
        const response = await fetch(endpoint, { signal: controller.signal });
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        const users = (await response.json()) as User[];
        setState({ status: "success", users, error: null });
      } catch (error) {
        if (error instanceof DOMException && error.name === "AbortError") return;
        setState({ status: "error", users: [], error: error instanceof Error ? error.message : "Unknown error" });
      }
    }
    void loadUsers();
    return () => controller.abort();
  }, [endpoint]);

  return state;
}
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { UserTable, type User } from "./UserTable";

const users: User[] = [
  { id: "1", name: "Masa", email: "masa@example.com", role: "admin", active: true },
  { id: "2", name: "Aiko", email: "aiko@example.com", role: "viewer", active: false },
];

describe("UserTable", () => {
  it("filters users and toggles active status", async () => {
    const user = userEvent.setup();
    const onRoleChange = vi.fn();
    const onToggleActive = vi.fn();
    render(<UserTable users={users} selectedRole="all" onRoleChange={onRoleChange} onToggleActive={onToggleActive} />);
    await user.selectOptions(screen.getByLabelText(/filter by role/i), "viewer");
    await user.click(screen.getByRole("button", { name: /apply/i }));
    await user.click(screen.getByRole("button", { name: /activate/i }));
    expect(onRoleChange).toHaveBeenCalledWith("viewer");
    expect(onToggleActive).toHaveBeenCalledWith("2");
  });
});

Prompt de revisión

Revisa este diff de React + TypeScript.
Comprueba límites de componentes, props excesivas, useEffect innecesario, mezcla de UI state y server state, labels y errores de formularios, cobertura con Testing Library y renders evitables en listas grandes.
No añadas librerías nuevas; propónlas solo si hace falta. Termina con comandos: npm test y npm run build.

Errores frecuentes

Los problemas más comunes son componentes demasiado pequeños sin valor real, useEffect para valores derivados, inputs sin label, botones de icono sin nombre accesible, errores comunicados solo por color y optimizaciones sin medición. Claude Code mejora cuando le pides “mínima abstracción útil” y “prueba desde el punto de vista del usuario”.

CTA y resultado

Para un equipo, documenta estas reglas en CLAUDE.md: límites, comandos de test, accesibilidad y patrones prohibidos de sobre-generación. ClaudeCodeLab ofrece formación y consultoría de Claude Code para aplicar este flujo a un repositorio React real, incluyendo revisión UI, Testing Library, rendimiento y formularios orientados a consulta o venta.

Resultado práctico: al usar este flujo en una UI administrativa de un sitio de contenidos, Masa redujo retrabajo porque Claude Code recibió límites, dueño del estado y expectativas de test antes de generar código. La pauta más estable fue generar diffs pequeños y verificables, no más componentes.

#Claude Code #React #frontend #components #Hooks
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.