50 Regras do React & Next.js
Regras essenciais para construir aplicações React 19 e Next.js em produção. Cobre arquitetura, performance, busca de dados, segurança e melhores práticas do ecossistema.
Busque em todas as páginas da documentação
Regras essenciais para construir aplicações React 19 e Next.js em produção. Cobre arquitetura, performance, busca de dados, segurança e melhores práticas do ecossistema.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
1. Por padrão, use Server Components. No App Router do Next.js (e ecossistemas React 19), componentes são Server Components por padrão. Adicione "use client" apenas quando precisar de interatividade, estado ou APIs do navegador. Isso minimiza o JavaScript no lado do cliente e melhora os tempos de carregamento.
2. Use o App Router exclusivamente para novos projetos. O Pages Router é legado. O App Router fornece layouts aninhados, streaming, melhor busca de dados e suporte completo a React Server Components.
3. Domine a fronteira cliente/servidor. Server Components podem renderizar Client Components (e passar props serializáveis). Client Components não podem importar Server Components. Nunca passe valores não serializáveis (funções, classes) através da fronteira.
Date, Map, Set4. Coloque a lógica perto dos componentes. Mantenha a busca de dados, estilos e utilitários relacionados próximos aos componentes que os utilizam. Mantenha efeitos colaterais previsíveis e, sempre que possível, priorize o servidor.
app/
dashboard/
page.tsx # Rota
dashboard-chart.tsx # Componente usado apenas aqui
actions.ts # Server Actions para esta rota
loading.tsx # UI de carregamento
5. Prefira composição em vez de herança ou estado complexo. Construa componentes pequenos, focados e reutilizáveis. Eleve o estado apenas quando necessário. Prefira estado local e dados gerenciados pelo servidor em vez de stores globais.
// Bom: composição com children
<Card>
<CardHeader>Título</CardHeader>
<CardBody>{conteudo}</CardBody>
</Card>
// Evitar: herança ou mega-componentes
class SpecialCard extends Card { ... }6. Adote TypeScript por padrão. Use tipagem estrita, genéricos para componentes e hooks, e o transformador JSX moderno. TypeScript captura erros precocemente e melhora a manutenibilidade em aplicações grandes.
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true
}
}7. Pense em Servidor + Cliente, não apenas "componentes". Projete com um modelo mental de renderização no servidor primeiro, e depois adicione interatividade no cliente com moderação. Performance é uma restrição de design, não um detalhe posterior.
| Camada | Lida com | Exemplos |
|---|---|---|
| Server Components | Busca de dados, conteúdo estático, SEO | Páginas de produto, dashboards, artigos |
| Client Components | Interatividade, estado, APIs do navegador | Formulários, modais, dropdowns, animações |
8. Use os novos hooks do React 19 com sabedoria. Aproveite as novas APIs para padrões comuns:
| Hook | Propósito |
|---|---|
useActionState | Estado de ação de formulário com pendente, erro, dados |
useOptimistic | Atualizações de UI otimistas durante ações assíncronas |
useFormStatus | Acessa o estado pendente do formulário pai |
use() | Desembrulha promises e contexto condicionalmente |
9. Abrace os React Server Components (RSCs) como base. RSCs permitem acesso direto ao backend, zero JS no cliente para partes estáticas e melhor streaming. Evite forçar tudo para o lado do cliente.
Benefícios dos RSCs:
10. Siga uma checklist de produção antes de implantar. Execute next build, teste com next start, otimize imagens e fontes, e verifique os Core Web Vitals.
# Checklist pré-implantação
next build # Verifica erros de build
next start # Testa o modo de produção localmente
npx lighthouse # Verifica métricas de performance11. Elimine waterfalls na busca de dados. Use fetches paralelos, limites Suspense e carregamento de dados no lado do servidor para evitar requisições sequenciais bloqueantes.
// Ruim: sequencial (waterfall)
const user = await getUser(id);
const posts = await getPosts(user.id);
// Bom: paralelo
const [user, posts] = await Promise.all([
getUser(id),
getPosts(id),
]);12. Confie no React Compiler (React Forget). No React 19, o compilador automaticamente memoiza onde é seguro. Escreva código mais simples sem useMemo e useCallback excessivos, a menos que a análise de performance mostre problemas.
// Antes: memoização manual em todo lugar
const filtered = useMemo(() => items.filter(predicate), [items, predicate]);
const handleClick = useCallback(() => doThing(id), [id]);
// Depois (com React Compiler): apenas escreva
const filtered = items.filter(predicate);
const handleClick = () => doThing(id);13. Use Suspense para busca de dados declarativa e estados de carregamento. Envolva seções dinâmicas com Suspense. Combine com streaming para renderização progressiva e melhor UX.
<Suspense fallback={<Skeleton />}>
<ProductDetails id={id} />
</Suspense>14. Aproveite o Partial Prerendering (PPR). No Next.js 15+, renderize estaticamente o "esqueleto" de uma página enquanto faz streaming das partes dinâmicas. Este é o melhor dos dois mundos para muitas aplicações.
// O esqueleto estático renderiza instantaneamente
// As partes dinâmicas chegam via streaming conforme resolvem
export default function Page() {
return (
<div>
<Header /> {/* Estático */}
<Suspense fallback={<Skeleton />}>
<LiveFeed /> {/* Dinâmico, via streaming */}
</Suspense>
<Footer /> {/* Estático */}
</div>
);
}15. Escolha a estratégia de renderização correta.
| Estratégia | Melhor para | Contrapartida |
|---|---|---|
| Estática (SSG) | Conteúdo público, páginas de marketing | Desatualizado até a reconstrução |
| ISR | Posts de blog, páginas de produto | Desatualizado dentro da janela de revalidação |
| SSR | Dados específicos do usuário, em tempo real | TTFB mais lento, mais carga no servidor |
| CSR | Ferramentas internas, dashboards com autenticação | Sem SEO, carregamento inicial mais lento |
16. Otimize imagens agressivamente. Use o componente Image do Next.js com sizes, formatos modernos (WebP/AVIF) e lazy loading. Comprima assets e evite waterfalls de fontes/CDNs de terceiros.
<Image
src="/hero.jpg"
alt="Imagem principal"
width={1200}
height={600}
sizes="(max-width: 768px) 100vw, 1200px"
priority // Acima da dobra? Use priority
/>17. Implemente cache e revalidação adequados. Use opções de cache do fetch, revalidatePath/revalidateTag, ou a diretiva use cache. Entenda as camadas de cache do Next.js:
| Camada de Cache | O quê | Duração |
|---|---|---|
| Request Memoization | Deduplica fetches idênticos em um único render | Requisição única |
| Data Cache | Armazena respostas de fetch | Até ser revalidado |
| Full Route Cache | Armazena páginas renderizadas inteiras | Até ser revalidado |
| Router Cache | Cache de rota do lado do cliente | Baseado na sessão |
18. Minimize o tamanho do bundle do cliente. Mantenha os Client Components pequenos e focados. Use imports dinâmicos para código do cliente pesado ou condicional.
import dynamic from "next/dynamic";
const HeavyChart = dynamic(() => import("./chart"), {
loading: () => <Skeleton className="h-64" />,
});19. Evite re-renders desnecessários. Com o Compiler, isso é menos manual, mas ainda assim analise com o React DevTools. Use chaves corretamente em listas. Não use o índice do array como chave para listas dinâmicas.
20. Faça streaming e hidratação seletivamente. Use limites Suspense para habilitar hidratação seletiva e performance percebida melhor. Usuários podem interagir com partes hidratadas enquanto outras seções ainda estão carregando.
21. Otimize para Core Web Vitals.
| Métrica | Alvo | Como |
|---|---|---|
| LCP (Largest Contentful Paint) | Abaixo de 2.5s | Imagens prioritárias, pré-carregar fontes, SSR |
| CLS (Cumulative Layout Shift) | Abaixo de 0.1 | Definir dimensões de imagem, evitar mudanças de layout |
| INP (Interaction to Next Paint) | Abaixo de 200ms | Bundles de cliente pequenos, useTransition |
22. Use Turbopack no desenvolvimento. Ele agora é estável e entrega HMR e builds significativamente mais rápidos no Next.js 15+.
next dev --turbopack23. Comprima e carregue sob demanda assets não críticos. Use imports dinâmicos para rotas e componentes, formatos modernos de imagem, e evite overhead de CSS-in-JS em tempo de execução sempre que possível (prefira Tailwind ou CSS Modules).
24. Monitore e analise em ambientes semelhantes à produção. Use as métricas embutidas do Next.js, Lighthouse e ferramentas como Vercel Analytics para capturar problemas de performance de usuários reais.
25. Reduza o JavaScript enviado ao cliente. Busque bundles menores através de RSCs, code splitting e tree-shaking. Server Components podem reduzir o JS do cliente em 30-50% em muitos casos.
26. Busque dados no servidor por padrão. Use Server Components ou Route Handlers. Evite busca de dados no lado do cliente para dados iniciais, quando possível.
// Server Component: acesso direto a dados
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const product = await db.product.findUnique({ where: { id } });
return <ProductDetails product={product} />;
}27. Use Server Actions para mutações. Elas simplificam formulários, lidam com transições assíncronas, estados pendentes e erros automaticamente no React 19 e Next.js. Prefira-as em vez de rotas de API tradicionais para muitos casos de uso.
"use server";
export async function createPost(formData: FormData) {
const title = formData.get("title") as string;
await db.post.create({ data: { title } });
revalidatePath("/posts");
}28. Prefira TanStack Query (ou SWR) para estado do servidor no lado do cliente. Combine com busca no servidor para cache e sincronização ótimos. Use busca no lado do cliente apenas para dados que mudam frequentemente após o carregamento inicial.
29. Gerencie formulários com Actions e atualizações otimistas. Use useOptimistic e useActionState para uma UX fluida sem boilerplate manual de carregamento e erros.
const [optimisticItems, addOptimistic] = useOptimistic(
items,
(state, newItem: Item) => [...state, { ...newItem, pending: true }]
);30. Mantenha o estado local, a menos que seja compartilhado. Evite o uso excessivo de gerenciadores de estado globais. Eleve o estado apenas quando realmente necessário.
| Tipo de Estado | Solução |
|---|---|
| Estado de UI (um componente) | useState |
| Estado local complexo | useReducer |
| Compartilhado entre irmãos | Elevar estado para o pai |
| Compartilhado pela aplicação | Zustand ou Context |
| Dados do servidor | Server Components, SWR, TanStack Query |
| Estado da URL | useSearchParams |
31. Deduplique requisições automaticamente. Next.js e React 19 lidam com muitos casos através da memoização de requisições. Garanta chaves de cache consistentes.
32. Use async/await naturalmente em Server Components. A busca de dados é síncrona durante a renderização no servidor. Server Components assíncronos são de primeira classe no React 19.
33. Valide entradas no servidor. Nunca confie em dados do cliente. Use schemas (Zod, etc.) em Server Actions ou Route Handlers.
"use server";
import { z } from "zod";
const schema = z.object({
email: z.string().email(),
name: z.string().min(2).max(100),
});
export async function createUser(formData: FormData) {
const result = schema.safeParse(Object.fromEntries(formData));
if (!result.success) return { error: result.error.flatten() };
// ... criar usuário
}34. Gerencie limites assíncronos com Suspense e limites de erro. Forneça fallbacks graciosos para carregamento e erros.
<ErrorBoundary fallback={<ErrorMessage />}>
<Suspense fallback={<Loading />}>
<AsyncComponent />
</Suspense>
</ErrorBoundary>35. Evite acesso direto a APIs do navegador em código compartilhado. Verifique "use client" e o ambiente quando necessário. Use guardas typeof window !== "undefined" com moderação, e prefira dividir em módulos de servidor e cliente.
36. Nunca exponha segredos ao cliente. Use variáveis de ambiente apenas para o servidor (sem prefixo NEXT_PUBLIC_ para dados sensíveis). Proxy chamadas de API através de Server Actions ou Route Handlers.
# .env
STRIPE_SECRET_KEY=sk_live_... # Apenas servidor
NEXT_PUBLIC_STRIPE_KEY=pk_live_... # Seguro para o cliente37. Proteja Server Actions. Proteja contra chamadas não autorizadas com verificações de autenticação adequadas. Mantenha as dependências atualizadas. Server Actions são endpoints HTTP públicos, então sempre verifique o usuário.
"use server";
import { auth } from "@/lib/auth";
export async function deletePost(id: string) {
const session = await auth();
if (!session) throw new Error("Unauthorized");
// ... deletar post
}38. Implemente autenticação e autorização adequadas. Use cookies httpOnly, Secure, SameSite para sessões. Valide no servidor. Nunca confie apenas em verificações do lado do cliente.
39. Sanitize e valide todas as entradas. Previna ataques XSS, CSRF (Server Actions têm proteção CSRF embutida via verificações de origem) e de injeção.
40. Siga uma checklist de segurança de produção:
npm audit41. Use pastas privadas (_folder) no App Router. Mantenha arquivos não-rota (utils, componentes) fora do sistema de roteamento.
app/
dashboard/
_components/ # Não é uma rota
_lib/ # Não é uma rota
page.tsx # Rota
42. Organize a estrutura do projeto de forma escalável.
src/
app/ # Rotas e layouts
components/ # Componentes de UI compartilhados
ui/ # Primitivas shadcn/ui
lib/ # Utilitários, constantes, tipos
hooks/ # Hooks customizados
actions/ # Server Actions compartilhados
43. Escreva componentes pequenos e de responsabilidade única. São mais fáceis de testar, otimizar e manter. Um componente deve fazer uma coisa bem. Se você precisa rolar para entendê-lo, divida-o.
44. Teste exaustivamente. Teste unitariamente hooks e componentes, teste de integração fluxos de dados e teste ponta a ponta (end-to-end) caminhos críticos. Inclua cenários de hidratação e streaming.
| Tipo de Teste | Ferramenta | O quê testar |
|---|---|---|
| Unitário | Vitest | Hooks, utilitários, Server Actions |
| Componente | React Testing Library | Interações do usuário, renderização |
| E2E | Playwright | Fluxos críticos do usuário, pagamentos |
45. Documente e revise as fronteiras. Marque claramente "use client", Server Actions e lógica de busca de dados em revisões de código. Torne a divisão cliente/servidor óbvia.
46. Integre funcionalidades de IA de forma ponderada. Proxy chamadas através do seu servidor (nunca exponha chaves de API no cliente). Use Server-Sent Events ou o Vercel AI SDK para streaming. Cache agressivamente e rastreie custos.
// Server Action com AI SDK
"use server";
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export async function chat(messages: Message[]) {
const result = await streamText({
model: openai("gpt-4o"),
messages,
});
return result.toDataStreamResponse();
}47. Aproveite ferramentas de metadados e SEO. Use a API metadata do Next.js, gere sitemaps e robots.txt dinamicamente, e garanta conteúdo renderizado no servidor para crawlers.
export const metadata: Metadata = {
title: "Nome do Produto",
description: "Descrição do produto para SEO",
openGraph: { images: ["/og-image.png"] },
};48. Mantenha-se atualizado, mas estável. Fixe versões principais quando necessário. Teste o React Compiler e novos comportamentos de cache incrementalmente. Leia os changelogs antes de atualizar.
49. Priorize acessibilidade e design inclusivo. Use HTML semântico, ARIA quando necessário, e teste com leitores de tela. Preste atenção especial a conteúdo dinâmico via streaming que pode não anunciar corretamente.
Verificações chave de acessibilidade:
alt significativo50. Trate performance e manutenibilidade como disciplinas contínuas. Analise regularmente, refatore em direção a padrões server-first, e use recursos da comunidade. Performance não é uma tarefa única. É uma prática contínua.
useState, useReducer) ou APIs do navegador"use client" preventivamenteDate, Map, SetUse Promise.all para executar buscas independentes em paralelo:
const [user, posts] = await Promise.all([
getUser(id),
getPosts(id),
]);useMemo e useCallback manuais na maioria dos casostype Props = {
params: Promise<{ id: string }>;
};
export default async function Page({ params }: Props) {
const { id } = await params;
// ...
}Defina um tipo de estado explícito para o valor de retorno da ação:
type FormState = {
error?: string;
data?: { id: string };
};
const [state, action, isPending] = useActionState<FormState, FormData>(
submitAction,
{ error: undefined, data: undefined }
);NEXT_PUBLIC_ é incluída no bundle do cliente em tempo de build"use server";
import { z } from "zod";
const schema = z.object({
email: z.string().email(),
name: z.string().min(2).max(100),
});
export async function createUser(formData: FormData) {
const result = schema.safeParse(Object.fromEntries(formData));
if (!result.success) return { error: result.error.flatten() };
}useOptimistic fornece feedback visual instantâneo enquanto uma ação assíncrona (ex: Server Action) está em progresso| Categoria | Principal Lição |
|---|---|
| Arquitetura | Server Components primeiro, Client Components apenas para interatividade |
| Performance | Fetching paralelo, streaming, PPR, Turbopack |
| Dados | Server Actions para mutações, Suspense para carregamento |
| Estado | Estado local por padrão, Zustand para compartilhado, URL para compartilhável |
| Formulários | useActionState + validação Zod + useOptimistic |
| Segurança | Nunca exponha segredos, valide no servidor, autenticação em cada ação |
| Testes | Unitário + componente + E2E cobrindo caminhos críticos |
| SEO | API Metadata, renderização no servidor, dados estruturados |
Revisado por Chris St. John·Última atualização: 7 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥