Communitygithub.com

react-performance

Padrões de otimização de desempenho para React e Next.js adaptados da Vercel Engineering.

O que é react-performance?

Este skill fornece um guia abrangente e priorizado de padrões de otimização de desempenho para React 18/19 e Next.js, adaptado das melhores práticas da Vercel Labs. Ele é organizado em oito categorias de prioridade, desde a eliminação crítica de waterfalls até padrões avançados, com o objetivo de ajudar desenvolvedores a auditar e refatorar código para melhorar a velocidade de carregamento de páginas, interações e métricas Core Web Vitals. O skill abrange desde a otimização do tamanho do bundle com imports diretos e carregamento dinâmico até o desempenho no servidor com `React.cache()`, e no cliente com gerenciamento eficiente de re-renderizações e hooks como `useMemo`, `useCallback` e `startTransition`. Cada seção inclui exemplos de código corrigidos e incorretos, além de um índice de prioridades para orientar quais otimizações focar primeiro durante revisões de código ou refatorações.

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

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

React Performance

Padrões de otimização de desempenho para React 18/19 e Next.js, adaptados de Vercel Labs react-best-practices (MIT, v1.0.0). Este skill organiza regras por prioridade e fornece orientação com árvore de decisão para revisão ativa de código e refatoração.

Quando Ativar

  • Escrevendo ou revisando código React/Next.js para desempenho
  • Diagnosticando carregamentos lentos de página, interações lentas ou alto uso de CPU no cliente
  • Auditando tamanho do bundle ou regressões nas Core Web Vitals do Lighthouse
  • Removendo waterfalls em Server Components / rotas de API
  • Reduzindo re-renderizações no lado do cliente
  • Otimizando listas longas, animações ou hidratação
  • Auditando escolhas de otimização em PRs que mexem em app/, pages/, components/ ou camadas de dados

Índice de Prioridade

PrioridadeCategoriaPrefixoQuando importa
1 — CRÍTICOEliminando Waterfallsasync-Sempre que await é seguido por await independente
2 — CRÍTICOOtimização do Tamanho do Bundlebundle-JS de carregamento inicial, imports por rota, bibliotecas de terceiros
3 — ALTODesempenho no Servidorserver-RSC, Server Actions, rotas de API, SSR
4 — MÉDIO-ALTOBusca de Dados no Clienteclient-SWR / TanStack Query / fetch bruto em hooks
5 — MÉDIOOtimização de Re-renderizaçãorerender-Atualizações de estado de alta frequência, propagação pai-filho
6 — MÉDIODesempenho de Renderizaçãorendering-Listas longas, animações, hidratação
7 — BAIXO-MÉDIODesempenho JavaScriptjs-Loops intensivos, alocações frequentes
8 — BAIXOPadrões Avançadosadvanced-Integração efeito-evento, refs estáveis

1. Eliminando Waterfalls (CRÍTICO)

"Waterfalls são o maior inimigo do desempenho" — cada await sequencial adiciona latência de rede completa.

Condições baratas antes de await

Verifique condições síncronas (props, env, flags fixas) antes de aguardar dados remotos.

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

// CORRETO — interrompe antes com condição síncrona barata primeiro
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);
}

Adie awaits até serem usados

Mova o await para dentro do ramo que o utiliza.

// INCORRETO — aguarda antes de decidir se precisa dos dados
const user = await getUser(id);
if (mode === "guest") return renderGuest();
return renderUser(user);

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

Promise.all para trabalho independente

// INCORRETO — sequencial
const user = await getUser(id);
const posts = await getPosts(id);
const followers = await getFollowers(id);

// CORRETO — paralelo
const [user, posts, followers] = await Promise.all([
  getUser(id),
  getPosts(id),
  getFollowers(id),
]);

Dependências parciais — comece cedo, aguarde tarde

// CORRETO — inicia todas as promessas, aguarda apenas quando cada resultado é necessário
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 para streaming

Coloque os limites de <Suspense> perto dos dados para que a página renderize o que puder enquanto sub-árvores mais lentas são transmitidas. A compensação: mudança de layout quando o conteúdo chega — reserve espaço (skeleton ou min-height).

Server Components: paralelização através de composição

// INCORRETO — awaits irmãos executam sequencialmente dentro de um componente
async function Page() {
  const user = await getUser();
  const cart = await getCart();
  return <View user={user} cart={cart} />;
}

// CORRETO — divida em filhos, React os executa em paralelo
export default async function Page() {
  return (
    <View>
      <UserSection />
      <CartSection />
    </View>
  );
}

2. Otimização do Tamanho do Bundle (CRÍTICO)

Imports diretos, não barris

Arquivos index.ts (barris) forçam o bundler a percorrer todo o grafo do módulo mesmo quando o tree-shaking remove a maior parte. Imports diretos economizam 200-800ms de JS de carregamento inicial em muitos aplicativos reais.

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

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

Next.js 13.5+ tem Optimize Package Imports que automatiza isso para pacotes listados — use-o; imports diretos manuais ainda são necessários para bibliotecas não listadas.

Caminhos estaticamente analisáveis

// INCORRETO — impede análise do bundler/trace
const mod = await import(`./pages/${name}`);

// CORRETO — explícito por ramo
const mod = name === "home" ? await import("./pages/home") : await import("./pages/about");

Imports dinâmicos para componentes pesados

import dynamic from "next/dynamic";

const HeavyChart = dynamic(() => import("./HeavyChart"), {
  loading: () => <Skeleton />,
  ssr: false, // quando apenas cliente
});

Adie scripts de terceiros

Carregue analytics, logs, widgets de suporte APÓS a hidratação. Use next/script com strategy="afterInteractive" (padrão) ou "lazyOnload".

Carregamento condicional de módulos

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

Pré-carregue ao passar o mouse/foco

Dispare <link rel="preload"> ou import() ao passar o mouse para que o bundle esteja no cache quando o usuário clicar.

3. Desempenho no Servidor (ALTO)

Autentique Server Actions como rotas de API

Toda função "use server" é um endpoint público. Autentique E autorize dentro da action — nunca dependa da proteção do Client Component que a chama.

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

React.cache() para desduplicação por requisição

import { cache } from "react";

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

React.cache remove duplicatas dentro de uma única requisição. Chamar getUser("1") de três Server Components na mesma renderização = uma consulta ao banco.

Cache LRU para dados entre requisições

Para dados que NÃO mudam por requisição (config, tabelas de consulta), armazene em cache fora do React com um cache LRU ou unstable_cache.

Evite serialização duplicada em props RSC

Quando um Server Component renderiza os mesmos dados em vários Client Components, os dados são serializados uma vez por consumidor. Eleve o Client Component e passe children.

Eleve E/S estática ao escopo do módulo

// CORRETO — executa uma vez no carregamento do módulo
const fontData = readFileSync(fontPath);

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

Sem estado mutável no escopo do módulo em RSC/SSR

Estado de módulo no servidor é compartilhado entre todas as requisições — uma condição de corrida entre usuários. Use armazenamento no escopo da requisição (headers(), cookies(), contexto assíncrono).

Minimize dados passados para Client Components

Serialize apenas o que o Cliente precisa. Remova campos, pagine, projete colunas na camada do banco de dados.

Paralelize buscas aninhadas com Promise.all por item

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

Use after() para trabalho não bloqueante

after() do Next.js 15 executa trabalho após o envio da resposta — logging, aquecimento de cache, analytics.

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

4. Busca de Dados no Cliente (MÉDIO-ALTO)

SWR / TanStack Query para desduplicação

Múltiplos componentes chamando useUser(id) devem compartilhar uma requisição de rede e uma entrada de cache. Use SWR ou TanStack Query — nunca crie seu próprio useEffect + fetch para dados compartilhados.

Desduplique listeners de eventos globais

// INCORRETO — cada componente adiciona o seu próprio
useEffect(() => {
  window.addEventListener("scroll", handler);
  return () => window.removeEventListener("scroll", handler);
}, []);

// CORRETO — um único listener compartilhado via hook + subject global
const useScroll = createScrollHook(); // subject singleton por baixo dos panos

Listeners passivos para scroll

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

Melhora a suavidade do scroll; o listener não pode usar preventDefault().

localStorage: versão + minimizar

  • Sempre armazene um campo version; incremente em mudanças de esquema e migre ou descarte dados antigos
  • Mantenha os payloads pequenos — localStorage é síncrono e bloqueia a thread principal

5. Otimização de Re-renderização (MÉDIO)

Não assine estado usado apenas em callbacks

// INCORRETO — re-renderiza toda vez que count muda
const count = useStore((s) => s.count);
const handler = () => doSomething(count);

// CORRETO — lê uma vez na chamada
const handler = () => {
  const count = useStore.getState().count;
  doSomething(count);
};

Extraia trabalho pesado para componentes memoizados

// CORRETO — filho re-renderiza apenas quando `items` muda
const Heavy = memo(function Heavy({ items }: { items: Item[] }) {
  return <Chart data={transform(items)} />;
});

Eleve props não primitivas padrão

// INCORRETO — novo array a cada render quebra memo
<List items={items ?? []} />

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

Dependências primitivas em effects

// INCORRETO — nova identidade de objeto a cada render
useEffect(() => {}, [{ id, name }]);

// CORRETO — primitivos
useEffect(() => {}, [id, name]);

Assine booleanos derivados, não valores brutos

// INCORRETO — re-renderiza para qualquer mudança no carrinho
const cart = useStore((s) => s.cart);
const hasItems = cart.length > 0;

// CORRETO — re-renderiza apenas quando a vacância muda
const hasItems = useStore((s) => s.cart.length > 0);

Derive durante a renderização, nunca via useEffect

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

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

setState funcional para callbacks estáveis

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

Inicializador de estado lazy para valores caros

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

Evite memo para primitivos simples

useMemo(() => x + 1, [x]) é overhead. Memo vale a pena para identidade de objeto e computação cara.

Divida hooks com deps independentes

// INCORRETO — ambos os seletores reexecutam se qualquer fonte mudar
const { a, b } = useSomething(source1, source2);

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

Mova lógica de interação para event handlers

Event handlers executam apenas na ação do usuário — useEffect reexecuta quando deps mudam.

startTransition para atualizações não urgentes

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

useDeferredValue para renderizações caras

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

useRef para valores transitórios frequentes

Para valores que mudam frequentemente mas não devem disparar re-renderização (timestamps, última tecla, acumuladores).

Não defina componentes dentro de componentes

// INCORRETO — Inner é um novo componente a cada render de Outer
function Outer() {
  const Inner = () => <span />;
  return <Inner />;
}

Cada render cria um novo tipo Inner, impedindo a reconciliação e desmontando filhos.

6. Desempenho de Renderização (MÉDIO)

Anima o wrapper, não o SVG

Transformar um <div> wrapper ao redor de um SVG é acelerado por GPU; transformar o SVG em si dispara paint.

content-visibility: auto para listas longas

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

O navegador pula a renderização fora da tela — grande ganho para listas com centenas de linhas.

Eleve JSX estático

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

SVG: reduza a precisão das coordenadas

d="M10.123456,20.654321" → d="M10.12,20.65". Cada dígito custa bytes; a diferença visual é sub-pixel.

Hidratação sem flicker via script inline

Para valores necessários antes da hidratação (tema, localidade), insira um <script> inline que define document.documentElement.dataset.* antes do React montar.

Suprima incompatibilidades de hidratação esperadas de forma estreita

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

Use APENAS para nós-folha conhecidamente divergentes — nunca em uma árvore contendo outros filhos.

<Activity> para mostrar/esconder ao invés de montar/desmontar

React 19 <Activity mode="visible|hidden"> mantém o estado da árvore e effects montados, mas esconde — mais barato que desmontar/remontar para abas e accordions.

Ternário sobre && para renderização condicional

// INCORRETO — `0` renderiza como nó de texto
{count && <Badge>{count}</Badge>}

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

useTransition para estados de carregamento

Emparelhe startTransition com a ação; React mostra a UI anterior como isPending enquanto o próximo estado computa.

Dicas de recurso do React DOM

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

…

[truncado para tradução]

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.

Habilidades Relacionadas