React 20 Chegou: Server Actions Estavel e Partial Prerendering Mudam Tudo
Olá HaWkers, React 20 finalmente está aqui e não é apenas mais uma atualização incremental. Esta versão representa a maior mudança arquitetural desde os Hooks. Server Actions agora são estáveis, Partial Prerendering elimina a tela branca, e o React Compiler faz memoização automática.
Se você achava que já sabia React, prepare-se para reaprender algumas coisas. Vamos explorar tudo que mudou.
Server Actions: A Estrela do React 20
Depois de meses em Canary, Server Actions finalmente graduaram para estável.
O Que Sao Server Actions
Server Actions permitem executar código no servidor diretamente de componentes React, sem criar API routes separadas.
// Antes: Precisava de API route + fetch no cliente
// pages/api/submit.js
export default async function handler(req, res) {
const data = JSON.parse(req.body);
await saveToDatabase(data);
res.json({ success: true });
}
// component.jsx
async function handleSubmit(formData) {
const res = await fetch('/api/submit', {
method: 'POST',
body: JSON.stringify(formData)
});
return res.json();
}// Depois: Server Action direto no componente
// actions.js
'use server'
export async function submitForm(formData) {
const name = formData.get('name');
const email = formData.get('email');
await saveToDatabase({ name, email });
return { success: true };
}
// component.jsx
import { submitForm } from './actions';
function ContactForm() {
return (
<form action={submitForm}>
<input name="name" required />
<input name="email" type="email" required />
<button type="submit">Enviar</button>
</form>
);
}
Beneficios Praticos
1. Menos Boilerplate:
// API routes eliminadas
// Sem fetch() manual
// Sem gerenciamento de loading states manual
// TypeScript end-to-end2. Progressive Enhancement:
// Formulário funciona mesmo sem JavaScript!
<form action={serverAction}>
{/* Se JS falhar, form ainda submete */}
</form>3. Integração Com useActionState:
'use client'
import { useActionState } from 'react';
import { submitForm } from './actions';
function Form() {
const [state, formAction, isPending] = useActionState(
submitForm,
{ message: '' }
);
return (
<form action={formAction}>
<input name="email" disabled={isPending} />
<button disabled={isPending}>
{isPending ? 'Enviando...' : 'Enviar'}
</button>
{state.message && <p>{state.message}</p>}
</form>
);
}
Partial Prerendering: Fim da Tela Branca
PPR (Partial Prerendering) resolve um dos problemas mais antigos do React: o tempo de carregamento inicial.
O Problema Antigo
Usuário clica no link
↓
Tela branca (carregando JS)
↓
Tela branca (hidratando)
↓
Conteúdo aparece (finalmente!)
Tempo total: 2-5 segundos em conexões lentasComo PPR Funciona
Usuário clica no link
↓
Conteúdo estático aparece IMEDIATAMENTE
↓
Partes dinâmicas fazem streaming enquanto carregam
↓
Página totalmente interativa
Tempo para primeiro conteúdo: < 100msImplementacao Pratica
// page.jsx - Partial Prerendering em ação
import { Suspense } from 'react';
export default function ProductPage({ params }) {
return (
<main>
{/* Parte estática - renderizada no build */}
<Header />
<ProductDetails id={params.id} />
{/* Parte dinâmica - streaming */}
<Suspense fallback={<ReviewsSkeleton />}>
<Reviews productId={params.id} />
</Suspense>
<Suspense fallback={<RecommendationsSkeleton />}>
<Recommendations userId={getCurrentUser()} />
</Suspense>
{/* Estático novamente */}
<Footer />
</main>
);
}
Metricas de Performance
Antes do PPR:
TTFB: 800ms
FCP: 2.1s
LCP: 3.2s
TTI: 4.5sDepois do PPR:
TTFB: 50ms
FCP: 150ms
LCP: 800ms
TTI: 1.2sEmpresas que adotaram PPR relatam melhorias massivas em Core Web Vitals.
React Compiler: Memoizacao Automatica
Lembra de toda aquela complexidade com useMemo, useCallback e React.memo? O React Compiler cuida disso automaticamente.
Antes: Memoizacao Manual
// O inferno da memoização manual
const MemoizedList = React.memo(function List({ items, onItemClick }) {
const sortedItems = useMemo(
() => items.sort((a, b) => a.name.localeCompare(b.name)),
[items]
);
const handleClick = useCallback(
(id) => {
onItemClick(id);
},
[onItemClick]
);
return (
<ul>
{sortedItems.map(item => (
<ListItem
key={item.id}
item={item}
onClick={handleClick}
/>
))}
</ul>
);
});
const ListItem = React.memo(function ListItem({ item, onClick }) {
return (
<li onClick={() => onClick(item.id)}>
{item.name}
</li>
);
});
Depois: Codigo Limpo
// React Compiler cuida da otimização
function List({ items, onItemClick }) {
const sortedItems = items.sort((a, b) =>
a.name.localeCompare(b.name)
);
return (
<ul>
{sortedItems.map(item => (
<ListItem
key={item.id}
item={item}
onClick={() => onItemClick(item.id)}
/>
))}
</ul>
);
}
function ListItem({ item, onClick }) {
return (
<li onClick={onClick}>
{item.name}
</li>
);
}
// Mesma performance, código 60% menorAtivando o Compiler
// babel.config.js
module.exports = {
plugins: [
['babel-plugin-react-compiler', {
// Opções
}]
]
};
// Ou em Next.js 15+
// next.config.js
module.exports = {
experimental: {
reactCompiler: true
}
};
Asset Loading API
Nova API para controle fino sobre carregamento de recursos.
Priorização Inteligente
import { preload, prefetch, preinit } from 'react-dom';
function App() {
// Preload crítico - carrega imediatamente
preload('/critical-image.jpg', { as: 'image' });
// Prefetch - carrega quando idle
prefetch('/next-page-data.json', { as: 'fetch' });
// Preinit - inicializa script
preinit('/analytics.js', { as: 'script' });
return <MainContent />;
}Carregamento Condicional
function ProductGallery({ products }) {
return (
<div>
{products.map((product, index) => {
// Primeiras 4 imagens: prioridade alta
if (index < 4) {
preload(product.image, {
as: 'image',
fetchPriority: 'high'
});
}
return <ProductCard key={product.id} product={product} />;
})}
</div>
);
}
Hooks Melhorados
React 20 traz melhorias significativas nos hooks existentes.
useDeferredValue Expandido
function SearchResults({ query }) {
// Defer atualizações não-urgentes
const deferredQuery = useDeferredValue(query);
const isStale = query !== deferredQuery;
return (
<div style={{ opacity: isStale ? 0.7 : 1 }}>
<Results query={deferredQuery} />
</div>
);
}useOptimistic Para UI Otimista
function TodoList({ todos, addTodo }) {
const [optimisticTodos, addOptimisticTodo] = useOptimistic(
todos,
(state, newTodo) => [...state, { ...newTodo, pending: true }]
);
async function handleAdd(formData) {
const newTodo = { text: formData.get('text') };
// UI atualiza imediatamente
addOptimisticTodo(newTodo);
// Servidor processa em background
await addTodo(newTodo);
}
return (
<form action={handleAdd}>
<input name="text" />
<ul>
{optimisticTodos.map(todo => (
<li
key={todo.id}
style={{ opacity: todo.pending ? 0.5 : 1 }}
>
{todo.text}
</li>
))}
</ul>
</form>
);
}
Migracao do React 19 Para 20
A migração é relativamente suave, mas há pontos de atenção.
Breaking Changes
// 1. forwardRef não é mais necessário
// Antes
const Input = forwardRef((props, ref) => (
<input ref={ref} {...props} />
));
// Depois
function Input({ ref, ...props }) {
return <input ref={ref} {...props} />;
}
// 2. Context como provider direto
// Antes
<ThemeContext.Provider value={theme}>
// Depois
<ThemeContext value={theme}>Checklist de Migracao
# 1. Atualize dependências
npm install react@20 react-dom@20
# 2. Atualize tipos TypeScript
npm install @types/react@20
# 3. Execute codemods
npx @react-codemod/update-react-imports
# 4. Verifique deprecations
npx react-upgrade-check
React Server Components Maduros
RSC saíram de experimental para padrão de produção.
Arquitetura Recomendada
app/
├── layout.jsx # Server Component
├── page.jsx # Server Component
├── components/
│ ├── Header.jsx # Server Component
│ ├── Footer.jsx # Server Component
│ └── client/
│ ├── Form.jsx # 'use client'
│ └── Modal.jsx # 'use client'
└── actions/
└── submit.js # 'use server'Regra de Ouro
// Padrão: Server Components
// - Não precisam de diretiva
// - Podem acessar banco de dados diretamente
// - Não adicionam JS ao bundle do cliente
// Client Components: apenas quando necessário
// - Interatividade (onClick, onChange)
// - Hooks de browser (useState, useEffect)
// - APIs do browser (localStorage, etc)
'use client' // Apenas quando realmente precisar
Performance: Numeros Reais
Comparativos de projetos migrados para React 20.
Bundle Size
React 19: 142 KB (gzipped)
React 20: 128 KB (gzipped)
Redução: 10%Core Web Vitals (Média)
Métrica | React 19 | React 20 | Melhoria
-----------|----------|----------|----------
LCP | 2.1s | 0.9s | -57%
FID | 95ms | 42ms | -56%
CLS | 0.12 | 0.05 | -58%
INP | 180ms | 75ms | -58%Memory Usage
Aplicação média:
React 19: 45MB heap
React 20: 32MB heap
Redução: 29%O Que Vem Por Ai
React 20 é só o começo. O roadmap indica:
React 21 (Preview)
- Activity API (substitui StrictMode)
- Built-in animation support
- Melhorias em Suspense
- Offscreen renderingEcossistema
- Next.js 16 com PPR padrão
- Remix full adoption de RSC
- React Native com nova arquitetura
Conclusao
React 20 não é apenas uma atualização, é uma reimaginação de como construímos aplicações web. Server Actions eliminam boilerplate, PPR acaba com telas brancas, e o Compiler remove a complexidade da otimização manual.
Para desenvolvedores, significa código mais simples e performance melhor. Para usuários, significa aplicações mais rápidas e responsivas.
Se você ainda não começou a migrar, agora é a hora. O futuro do React é server-first, streaming-enabled e automaticamente otimizado.
Se você quer continuar acompanhando as novidades do ecossistema, recomendo dar uma olhada em outro artigo: TypeScript 7 Nativo em Go: 10x Mais Rápido onde exploramos outra grande mudança que está transformando o desenvolvimento frontend.

