Communitygithub.com

react-performance

Modèles d'optimisation des performances pour React et Next.js, adaptés de l'ingénierie Vercel.

Qu'est-ce que react-performance ?

Ce skill fournit des règles d'optimisation des performances classées par priorité pour React 18/19 et Next.js, adaptées des meilleures pratiques de Vercel Labs. Il vous guide pour éliminer les goulots d'étranglement lors de la revue de code et du refactoring : élimination des waterfalls (requêtes séquentielles), optimisation de la taille du bundle (imports directs, chargements dynamiques), performances côté serveur (authentification des Server Actions, déduplication avec `React.cache`, chargement différé), récupération de données côté client (SWR, TanStack Query), optimisation des re-rendus (mémorisation, hooks, `startTransition`), et performances de rendu (listes longues, animations, SVG). Il inclut des exemples de code concrets (avant/après) et un tableau de priorité pour se concentrer sur les optimisations à fort impact. Ce skill est conçu pour être utilisé dans des environnements comme Cursor, Claude Code, ou d'autres agents de codage, afin d'auditer et d'améliorer les performances des applications React et Next.js.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/react-performance

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Performances React

Modèles d'optimisation des performances pour React 18/19 et Next.js, adaptés de Vercel Labs react-best-practices (MIT, v1.0.0). Ce skill organise les règles par priorité et fournit un arbre de décision pour la revue de code active et le refactoring.

Quand activer

  • Écrire ou réviser du code React/Next.js pour les performances
  • Diagnostiquer des chargements de page lents, des interactions lentes ou une utilisation élevée du CPU côté client
  • Auditer la taille du bundle ou les régressions Lighthouse Core Web Vitals
  • Supprimer les waterfalls dans les Server Components / routes API
  • Réduire les re-rendus côté client
  • Optimiser les longues listes, les animations ou l'hydratation
  • Auditer les choix d'optimisation dans les PRs qui touchent app/, pages/, components/ ou les couches de données

Index de priorité

PrioritéCatégoriePréfixeQuand cela compte
1 — CRITIQUEÉliminer les waterfallsasync-Chaque fois que await est suivi d'un await indépendant
2 — CRITIQUEOptimisation de la taille du bundlebundle-Chargement initial JS, imports au niveau des routes, bibliothèques tierces
3 — ÉLEVÉEPerformances côté serveurserver-RSC, Server Actions, routes API, SSR
4 — MOYENNE-ÉLEVÉERécupération de données côté clientclient-SWR / TanStack Query / fetch brut dans les hooks
5 — MOYENNEOptimisation des re-rendusrerender-Mises à jour d'état à haute fréquence, fan-out parent-enfant
6 — MOYENNEPerformances de rendurendering-Longues listes, animations, hydratation
7 — FAIBLE-MOYENNEPerformances JavaScriptjs-Boucles chaudes, allocations fréquentes
8 — FAIBLEModèles avancésadvanced-Intégration effet-événement, refs stables

1. Éliminer les waterfalls (CRITIQUE)

« Les waterfalls sont le tueur de performances numéro un » — chaque await séquentiel ajoute la latence réseau complète.

Conditions peu coûteuses avant await

Vérifiez les conditions synchrones (props, env, drapeaux codés en dur) avant d'attendre des données distantes.

// INCORRECT
async function Page({ id }: { id: string }) {
  const flag = await getFlag("show-page");
  if (!flag || !id) return null;
  const data = await getData(id);
  // ...
}

// CORRECT — court-circuit sur condition synchrone peu coûteuse en premier
async function Page({ id }: { id: string }) {
  if (!id) return null;
  const flag = await getFlag("show-page");
  if (!flag) return null;
  const data = await getData(id);
}

Reporter les awaits jusqu'à leur utilisation

Déplacez await dans la branche qui l'utilise.

// INCORRECT — attend avant de décider si les données sont nécessaires
const user = await getUser(id);
if (mode === "guest") return renderGuest();
return renderUser(user);

// CORRECT
if (mode === "guest") return renderGuest();
const user = await getUser(id);
return renderUser(user);

Promise.all pour les tâches indépendantes

// INCORRECT — séquentiel
const user = await getUser(id);
const posts = await getPosts(id);
const followers = await getFollowers(id);

// CORRECT — parallèle
const [user, posts, followers] = await Promise.all([
  getUser(id),
  getPosts(id),
  getFollowers(id),
]);

Dépendances partielles — commencer tôt, attendre tard

// CORRECT — lancez toutes les promesses, attendez seulement quand chaque résultat est nécessaire
const userP = getUser(id);
const postsP = getPosts(id);
const profile = await getProfile(id);
if (profile.private) return null;
const [user, posts] = await Promise.all([userP, postsP]);

Suspense pour le streaming

Poussez les limites <Suspense> près des données afin que la page affiche ce qu'elle peut pendant que les sous-arbres plus lents arrivent en streaming. Le compromis : décalage de mise en page lorsque le contenu arrive — réservez de l'espace (skeleton ou min-height).

Server Components : parallélisation par composition

// INCORRECT — les awaits frères s'exécutent séquentiellement dans un seul composant
export default async function Page() {
  const user = await getUser();
  const cart = await getCart();
  return <View user={user} cart={cart} />;
}

// CORRECT — divisez en enfants, React les exécute en parallèle
export default async function Page() {
  return (
    <View>
      <UserSection />
      <CartSection />
    </View>
  );
}

2. Optimisation de la taille du bundle (CRITIQUE)

Imports directs, pas de barils

Les fichiers baril index.ts forcent le bundler à parcourir tout le graphe de modules même si l'élimination du code mort supprime la plupart de son contenu. Les imports directs permettent d'économiser 200 à 800 ms de JS de chargement initial dans de nombreuses applications réelles.

// INCORRECT
import { Button, Card, Modal } from "@/components";

// CORRECT
import { Button } from "@/components/Button";
import { Card } from "@/components/Card";
import { Modal } from "@/components/Modal";

Next.js 13.5+ dispose d'Optimize Package Imports qui automatise cela pour les packages répertoriés — utilisez-le ; les imports directs manuels sont toujours nécessaires pour les bibliothèques non répertoriées.

Chemins analysables statiquement

// INCORRECT — empêche l'analyse du bundler/trace
const mod = await import(`./pages/${name}`);

// CORRECT — explicite par branche
const mod = name === "home" ? await import("./pages/home") : await import("./pages/about");

Imports dynamiques pour les composants lourds

import dynamic from "next/dynamic";

const HeavyChart = dynamic(() => import("./HeavyChart"), {
  loading: () => <Skeleton />,
  ssr: false, // lorsque client uniquement
});

Différer les scripts tiers

Chargez les analytics, la journalisation, les widgets d'assistance APRÈS l'hydratation. Utilisez next/script avec strategy="afterInteractive" (par défaut) ou "lazyOnload".

Chargement conditionnel de modules

if (user.role === "admin") {
  const { AdminPanel } = await import("./admin/AdminPanel");
  // ...
}

Précharger au survol/au focus

Déclenchez <link rel="preload"> ou import() au survol pour que le bundle soit dans le cache au moment où l'utilisateur clique.

3. Performances côté serveur (ÉLEVÉE)

Authentifier les Server Actions comme les routes API

Chaque fonction "use server" est un point de terminaison public. Authentifiez ET autorisez à l'intérieur de l'action — ne vous fiez jamais au contrôle du Client Component appelant.

"use server";
export async function deleteUser(formData: FormData) {
  const session = await getSession();
  if (!session?.user) throw new Error("Non autorisé");
  const targetId = String(formData.get("id"));
  if (session.user.role !== "admin" && session.user.id !== targetId) {
    throw new Error("Interdit");
  }
  await db.user.delete({ where: { id: targetId } });
}

React.cache() pour la déduplication par requête

import { cache } from "react";

export const getUser = cache(async (id: string) => {
  return db.user.findUnique({ where: { id } });
});

React.cache déduplique au sein d'une seule requête. Appeler getUser("1") depuis trois Server Components dans le même rendu = une requête DB.

Cache LRU pour les données inter-requêtes

Pour les données qui NE changent PAS par requête (configuration, tables de correspondance), mettez en cache en dehors de React avec un cache LRU ou unstable_cache.

Éviter la sérialisation en double dans les props RSC

Lorsqu'un Server Component rend les mêmes données dans plusieurs Client Components, les données sont sérialisées une fois par consommateur. Remontez le Client Component et passez des enfants.

Déplacer les E/S statiques vers la portée du module

// CORRECT — s'exécute une fois au chargement du module
const fontData = readFileSync(fontPath);

export async function Page() {
  return <Banner font={fontData} />;
}

Pas d'état mutable au niveau du module dans RSC/SSR

L'état du module sur le serveur est partagé entre toutes les requêtes — une condition de concurrence entre les utilisateurs. Utilisez un stockage limité à la requête (headers(), cookies(), contexte asynchrone) à la place.

Minimiser les données passées aux Client Components

Sérialisez uniquement ce dont le Client a besoin. Supprimez les champs, paginez, projetez les colonnes au niveau de la couche DB.

Paralléliser les fetchs imbriqués avec Promise.all par élément

const users = await getUsers();
const enriched = await Promise.all(
  users.map(async (u) => ({ ...u, posts: await getPostsFor(u.id) })),
);

Utiliser after() pour les tâches non bloquantes

after() de Next.js 15 exécute le travail après l'envoi de la réponse — journalisation, réchauffement du cache, analytics.

import { after } from "next/server";
export async function GET() {
  const data = await getData();
  after(() => logAnalytics(data));
  return Response.json(data);
}

4. Récupération de données côté client (MOYENNE-ÉLEVÉE)

SWR / TanStack Query pour la déduplication

Plusieurs composants appelant useUser(id) doivent partager une seule requête réseau et une seule entrée de cache. Utilisez SWR ou TanStack Query — n'implémentez jamais votre propre useEffect + fetch pour des données partagées.

Dédupliquer les écouteurs d'événements globaux

// INCORRECT — chaque composant ajoute le sien
useEffect(() => {
  window.addEventListener("scroll", handler);
  return () => window.removeEventListener("scroll", handler);
}, []);

// CORRECT — écouteur partagé unique via un hook + sujet global
const useScroll = createScrollHook(); // sujet singleton sous le capot

Écouteurs passifs pour le scroll

window.addEventListener("scroll", handler, { passive: true });

Améliore la fluidité du défilement ; l'écouteur ne peut pas appeler preventDefault().

localStorage : version + minimiser

  • Stockez toujours un champ version ; incrémentez-le lors d'un changement de schéma et migrez ou jetez les anciennes données
  • Gardez les charges utiles petites — localStorage est synchrone et bloque le thread principal

5. Optimisation des re-rendus (MOYENNE)

Ne pas s'abonner à un état utilisé uniquement dans les callbacks

// INCORRECT — se re-rend à chaque fois que count change
const count = useStore((s) => s.count);
const handler = () => doSomething(count);

// CORRECT — lu une fois à l'appel
const handler = () => {
  const count = useStore.getState().count;
  doSomething(count);
};

Extraire les travaux coûteux dans des composants mémorisés

// CORRECT — l'enfant se re-rend uniquement lorsque `items` change
const Heavy = memo(function Heavy({ items }: { items: Item[] }) {
  return <Chart data={transform(items)} />;
});

Remonter les props non primitives par défaut

// INCORRECT — nouveau tableau à chaque rendu, ce qui casse memo
<List items={items ?? []} />

// CORRECT
const EMPTY: Item[] = [];
<List items={items ?? EMPTY} />

Dépendances primitives dans les effets

// INCORRECT — nouvel identifiant d'objet à chaque rendu
useEffect(() => {}, [{ id, name }]);

// CORRECT — primitives
useEffect(() => {}, [id, name]);

S'abonner à des booléens dérivés, pas à des valeurs brutes

// INCORRECT — se re-rend pour tout changement de panier
const cart = useStore((s) => s.cart);
const hasItems = cart.length > 0;

// CORRECT — se re-rend uniquement lorsque le booléen bascule
const hasItems = useStore((s) => s.cart.length > 0);

Dériver pendant le rendu, jamais via useEffect

// INCORRECT
const [full, setFull] = useState("");
useEffect(() => setFull(`${first} ${last}`), [first, last]);

// CORRECT
const full = `${first} ${last}`;

setState fonctionnel pour des callbacks stables

// CORRECT
const increment = useCallback(() => setCount((c) => c + 1), []);

Initialiseur d'état paresseux pour les valeurs coûteuses

const [tree] = useState(() => parseTree(largeInput));

Éviter memo pour les primitives simples

useMemo(() => x + 1, [x]) est de la surcharge. Memo est utile pour l'identité d'objet et les calculs coûteux.

Diviser les hooks avec des dépendances indépendantes

// INCORRECT — les deux sélecteurs se réexécutent si l'une ou l'autre source change
const { a, b } = useSomething(source1, source2);

// CORRECT
const a = useA(source1);
const b = useB(source2);

Déplacer la logique d'interaction dans les gestionnaires d'événements

Les gestionnaires d'événements s'exécutent uniquement sur l'action de l'utilisateur — useEffect se réexécute à chaque changement de dépendance.

startTransition pour les mises à jour non urgentes

const [pending, startTransition] = useTransition();
startTransition(() => setFilters(newFilters));

useDeferredValue pour les rendus coûteux

const deferredQuery = useDeferredValue(query);
const results = useMemo(() => expensiveSearch(deferredQuery), [deferredQuery]);

useRef pour les valeurs transitoires fréquentes

Pour les valeurs qui changent souvent mais ne doivent pas déclencher de re-rendu (horodatages, dernière clé, accumulateurs).

Ne pas définir de composants à l'intérieur de composants

// INCORRECT — Inner est un nouveau composant à chaque rendu d'Outer
function Outer() {
  const Inner = () => <span />;
  return <Inner />;
}

Chaque rendu crée un nouveau type Inner, ce qui empêche la réconciliation et démonte les enfants.

6. Performances de rendu (MOYENNE)

Animer le wrapper, pas le SVG

Transformer une <div> wrapper autour d'un SVG est accéléré par le GPU ; transformer le SVG lui-même déclenche le paint.

content-visibility: auto pour les longues listes

.row { content-visibility: auto; contain-intrinsic-size: auto 80px; }

Le navigateur ignore le rendu hors écran — un gain majeur pour les listes avec des centaines de lignes.

Remonter le JSX statique

const STATIC_HEADER = <h1>Titre</h1>;
function Page() {
  return <>{STATIC_HEADER}<Body /></>;
}

SVG : réduire la précision des coordonnées

d="M10.123456,20.654321" → d="M10.12,20.65". Chaque chiffre coûte des octets ; la différence visuelle est inférieure au pixel.

Pas de scintillement d'hydratation via script en ligne

Pour les valeurs nécessaires avant l'hydratation (thème, locale), intégrez un <script> qui définit document.documentElement.dataset.* avant que React ne monte.

Supprimer les incohérences d'hydratation attendues de manière étroite

<time suppressHydrationWarning>{new Date().toLocaleString()}</time>

Utilisez UNIQUEMENT pour les nœuds feuilles connus pour diverger — jamais sur un arbre contenant d'autres enfants.

<Activity> pour afficher/masquer au lieu de monter/démonter

React 19 <Activity mode="visible|hidden"> maintient l'état et les effets de l'arbre montés mais masqués — moins coûteux que le démontage/remontage pour les onglets et les accordéons.

Opérateur ternaire plutôt que && pour le rendu conditionnel

// INCORRECT — `0` s'affiche comme un nœud de texte
{count && <Badge>{count}</Badge>}

// CORRECT
{count > 0 ? <Badge>{count}</Badge> : null}

useTransition pour les états de chargement

Associez startTransition à l'action ; React affiche l'interface utilisateur précédente comme isPending pendant que l'état suivant est calculé.

Indices de ressources React DOM

import { preload, preconnect } from "react-dom";
preload("/api/critical", { as: "fetch" });
preconnect("https://api.example.com")

…

[tronqué pour la traduction]

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Skills associés