O que é Preact?
Preact é uma alternativa minúscula ao React. Ele implementa o mesmo modelo de componentes, os mesmos hooks e um virtual DOM, com cerca de três kilobytes gzipped. Para a maioria dos componentes, o código que você escreve para React funciona no Preact com pouca ou nenhuma alteração.
Esse tamanho é o ponto principal. Quando você está incorporando um widget em uma página que não controla totalmente, construindo uma interface onde a performance é crítica ou simplesmente quer manter seu orçamento de JavaScript reduzido, alguns kilobytes de framework podem fazer uma diferença mensurável. O Preact oferece o modelo familiar sem o peso.
Componentes e hooks
Componentes Preact são funções que retornam JSX, e os hooks vêm de preact/hooks.
// Search.jsx
import { useState } from "preact/hooks";
export function Search({ onSearch }) {
const [query, setQuery] = useState("");
return (
<form
onSubmit={(event) => {
event.preventDefault();
onSearch(query);
}}
>
<input
value={query}
onInput={(event) => setQuery(event.currentTarget.value)}
/>
</form>
);
}
useState, useEffect, useRef, useContext, useMemo e useCallback funcionam exatamente como você esperaria. As principais diferenças são pequenas: o Preact suporta tanto class quanto className, e utiliza nomes de eventos nativos como onInput e onDblClick.
Preact Signals
Signals são a primitiva de reatividade de primeira classe do Preact. Um signal armazena um valor e, quando lido dentro do JSX, inscreve aquela parte do DOM a ele. Alterar o valor atualiza o DOM diretamente — sem a necessidade de re-renderizar o componente.
// Counter.jsx
import { signal, computed } from "@preact/signals";
const count = signal(0);
const double = computed(() => count.value * 2);
export function Counter() {
return (
<div>
<button onClick={() => count.value++}>
Count: {count}
</button>
<p>Double: {double}</p>
</div>
);
}
Como os signals vivem fora da árvore de componentes, você pode compartilhá-los e mutá-los de qualquer lugar, incluindo módulos simples e manipuladores de eventos. Eles são a maneira recomendada de gerenciar estados que mudam com frequência.
A camada de compatibilidade
O pacote preact/compat mapeia a API do React para o Preact. Crie aliases de react e react-dom para ele no seu bundler e a maioria das bibliotecas React funcionará sem alterações.
// vite.config.js
import { defineConfig } from "vite";
import preact from "@preact/preset-vite";
export default defineConfig({
plugins: [preact()],
resolve: {
alias: {
react: "preact/compat",
"react-dom": "preact/compat",
"react-dom/client": "preact/compat/client",
},
},
});
É assim que projetos Preact utilizam o ecossistema React — bibliotecas de componentes, roteamento, gerenciadores de estado e mais — enquanto ainda entregam um runtime menor. A contrapartida é um pequeno overhead da camada de compatibilidade, mas que ainda é muito menor do que o próprio React.
Sem etapa de build com htm
Se você quiser pular a etapa de build completamente, a biblioteca htm oferece uma alternativa de tagged template ao JSX.
// app.js
import { h, render } from "preact";
import htm from "htm";
const html = htm.bind(h);
function App({ name }) {
return html`<h1>Hello, ${name}!</h1>`;
}
render(html`<${App} name="Ada" />`, document.body);
Isso é útil para progressive enhancement, demos rápidas e para embutir pequenas ilhas interativas em uma página renderizada no servidor.
Diferenças em relação ao React
A sobreposição é grande, mas alguns detalhes diferem:
- O Preact utiliza nomes de eventos nativos do DOM, portanto
onInputeonDblClicksubstituem alguns nomes específicos do React. - Tanto
classquantoclassNamefuncionam, e tantoforquantohtmlForsão aceitos. - Não existe o synthetic event pooling, pois o Preact nunca utilizou pooling de eventos.
- Alguns recursos mais recentes do React, como partes da API de React Server Components, não estão implementados.
- Os tipos JSX do TypeScript vêm do Preact e precisam de aliasing ao utilizar o compat.
Para componentes e hooks do dia a dia, você raramente notará a diferença.
Quando usar Preact
O Preact se destaca quando o tamanho e o custo de inicialização são prioridades: widgets incorporáveis, páginas de marketing com pouca interatividade, sites de conteúdo e aplicações com orçamentos de performance rigorosos. Ele também é um alvo de migração suave para bases de código React existentes que precisam se tornar menores.
Se você depende de ferramentas específicas do React, funcionalidades de última geração ou de uma biblioteca que dependa de internals do React, permanecer no React pode gerar menos atrito. A boa notícia é que a sobreposição de API significa que essa decisão não é um caminho sem volta.
Melhores práticas
- Use signals para estados que mudam com frequência ou que são compartilhados fora da árvore.
- Recorra ao
preact/compatapenas quando precisar de pacotes do ecossistema React. - Crie aliases para os tipos do React, bem como para os módulos de runtime, ao utilizar compat.
- Mantenha os componentes pequenos e evite re-renders desnecessários lendo os signals no ponto de uso.
- Meça o impacto real no bundle — a economia é significativa, mas o seu próprio código ainda é o fator dominante.
- Prefira
preact/preset-vitepara configurar o build corretamente logo de início.
Erros comuns
- Misturar pacotes React e Preact sem o alias de compatibilidade.
- Esquecer de criar o alias para
react-dom/client, o que quebra a nova API de root. - Assumir que toda biblioteca React funciona sem testar a camada de compatibilidade.
- Usar signals em excesso e renderizar novamente componentes que poderiam ler um signal diretamente.
- Tratar o Preact como idêntico em funcionalidades ao React e se surpreender com algum caso isolado (edge case).
- Adicionar Preact para reduzir o tamanho do bundle e depois instalar uma dependência pesada que anula esse ganho.
Próximos passos
O Preact é a resposta pragmática para quando o modelo do React é o ideal, mas o seu tamanho não. Compare-o com React e Svelte, configure-o com Vite e mantenha seus fundamentos de JavaScript em dia. Depois, tente incorporar um pequeno widget Preact em uma página HTML simples para ver quão baixo é o custo de performance.