Bonnes pratiques React
Gardez le code React simple, sécurisé, accessible et facile à modifier par des agents. Utilisez ce guide avec React Doctor avant de pousser ou fusionner des PR.
Règles par défaut
Section intitulée « Règles par défaut »- Keep components small and named after product concepts.
- Put server data in TanStack Query or route loaders, not duplicated local state.
- Derive values during render; do not mirror props/query data into
useState+useEffect. - Utilisez
useEffectonly for real side effects: subscriptions, imperative APIs, analytics, or external synchronization. - Move static config outside components: table columns, labels, nav items, schema-like arrays.
- Memoize only when it protects expensive work or stable props for memoized children.
- Prefer custom hooks for reusable behavior, not for hiding one-off component logic.
- Keep forms typed with schema validation and visible labels.
- Give icon-only buttons an
aria-label. - Avoid
dangerouslySetInnerHTML; if unavoidable, sanitize at the boundary and document why.
Récupération de données
Section intitulée « Récupération de données »Prefer these patterns:
const { data, isPending } = useQuery({ ...orpc.companies.list.queryOptions({ input: filters }),});const mutation = useMutation({ ...orpc.companies.update.mutationOptions(), onSuccess: () => queryClient.invalidateQueries({ queryKey: orpc.companies.key() }),});Avoid:
const [items, setItems] = useState<Item[]>([]);
useEffect(() => { fetchItems().then(setItems);}, []);Forme des composants
Section intitulée « Forme des composants »Good default:
const columns: ColumnDef<User>[] = [ { accessorKey: "email", header: "Email" },];
export function UsersTable({ users }: { users: User[] }) { return <DataTable columns={columns} data={users} />;}Avoid recreating static arrays or nested components every render:
export function UsersPage() { const columns = [{ accessorKey: "email", header: "Email" }]; function RowActions() { return <Button>...</Button>; } return <DataTable columns={columns} />;}Sécurité et accessibilité
Section intitulée « Sécurité et accessibilité »- No raw HTML unless sanitized.
- No secrets in client code or
VITE_PUBLIC_*values. - Validate user input on the server even when forms validate on the client.
- Utilisez semantic elements before ARIA.
- Every form input needs a label or accessible name.
- Every destructive action needs a confirmation or undo path.
- External links should use
rel="noreferrer"when opening a new tab.
Modèle de configuration React Doctor
Section intitulée « Modèle de configuration React Doctor »Add this to React app repos as react-doctor.config.json:
{ "lint": true, "deadCode": true, "verbose": true, "diff": false, "failOn": "error", "ignore": { "rules": [], "files": ["src/routeTree.gen.ts", "src/generated/**"], "overrides": [] }}Only ignore rules narrowly. Prefer file-level generated-code ignores over global rule ignores.
Commandes requises
Section intitulée « Commandes requises »{ "scripts": { "doctor:react": "react-doctor .", "doctor:react:diff": "react-doctor . --diff main", "doctor:react:staged": "react-doctor . --staged" }}Run before pushing UI work:
pnpm doctor:react:diffMerge rule: React Doctor score should be 75+; scores below 50 block merge unless explicitly approved.
Checklist agent
Section intitulée « Checklist agent »Before handing off React work, an agent should confirm:
- no derived state in effects
- no missing effect cleanup
- no nested component definitions
- no index keys for mutable lists
- no unlabelled icon-only buttons
- no unsafe HTML or client-side secrets
-
pnpm doctor:react:diffpasses or findings are documented