¿Qué es Preact?
Preact es una alternativa diminuta a React. Implementa el mismo modelo de componentes, los mismos hooks y un virtual DOM, en aproximadamente tres kilobytes gzipped. Para la mayoría de los componentes, el código que escribes para React funciona en Preact con pocos o ningún cambio.
Ese tamaño es precisamente el objetivo. Cuando estás integrando un widget en una página que no controlas totalmente, construyendo una interfaz donde el rendimiento es crítico o simplemente quieres mantener reducido tu presupuesto de JavaScript, unos pocos kilobytes de framework pueden marcar una diferencia medible. Preact te ofrece el modelo familiar sin el peso.
Componentes y hooks
Los componentes de Preact son funciones que devuelven JSX, y los hooks provienen 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 y useCallback se comportan tal como esperarías. Las principales diferencias son pequeñas: Preact soporta tanto class como className, y utiliza nombres de eventos nativos como onInput y onDblClick.
Preact Signals
Los Signals son la primitiva de reactividad de primer nivel de Preact. Un signal contiene un valor y, cuando se lee dentro de JSX, suscribe esa parte del DOM a dicho valor. Al cambiar el valor, el DOM se actualiza directamente, sin necesidad de que el componente se vuelva a renderizar.
// 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>
);
}
Debido a que los signals viven fuera del árbol de componentes, puedes compartirlos y mutarlos desde cualquier lugar, incluyendo módulos simples y manejadores de eventos. Son la forma recomendada de gestionar estados que cambian con frecuencia.
La capa de compatibilidad
El paquete preact/compat mapea la API de React hacia Preact. Crea un alias de react y react-dom hacia este en tu bundler, y la mayoría de las librerías de React funcionarán sin cambios.
// 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",
},
},
});
Así es como los proyectos de Preact utilizan el ecosistema de React —librerías de componentes, enrutamiento, gestores de estado y más— mientras siguen distribuyendo un runtime más pequeño. La contrapartida es una ligera sobrecarga debida a la capa de compatibilidad, pero sigue siendo mucho menor que la de React.
Sin paso de compilación con htm
Si prefieres omitir el proceso de build por completo, la librería htm ofrece una alternativa a JSX mediante tagged templates.
// 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);
Esto es muy útil para el progressive enhancement, demos rápidas y para embeber una pequeña isla interactiva en una página renderizada en el servidor.
Diferencias con React
El solapamiento es amplio, pero algunos detalles varían:
- Preact utiliza nombres de eventos nativos del DOM, por lo que
onInputyonDblClicksustituyen a algunos nombres específicos de React. - Tanto
classcomoclassNamefuncionan, y se aceptan tantoforcomohtmlFor. - No existe el pooling de eventos sintéticos, ya que Preact nunca ha implementado el pooling de eventos.
- Algunas funciones más recientes de React, como partes de la API de React Server Components, no están implementadas.
- Los tipos de JSX de TypeScript provienen de Preact y requieren un alias cuando se utiliza compat.
Para los componentes y hooks del día a día, rara vez notarás la diferencia.
Cuándo usar Preact
Preact destaca cuando el tamaño y el coste de inicio son prioridades: widgets embebibles, páginas de marketing con poca interactividad, sitios de contenido y aplicaciones con presupuestos de rendimiento estrictos. También es un objetivo de migración sencillo para una base de código de React existente que necesite reducir su tamaño.
Si dependes de herramientas específicas de React, funciones experimentales o una librería que dependa de los internos de React, permanecer en React puede generar menos fricción. La buena noticia es que la similitud de la API significa que esta decisión no es un camino sin retorno.
Mejores prácticas
- Usa signals para el estado que cambie frecuentemente o que se comparta fuera del árbol.
- Recurre a
preact/compatsolo cuando necesites paquetes del ecosistema de React. - Crea alias tanto para los tipos de React como para los módulos de runtime al usar compat.
- Mantén los componentes pequeños y evita re-renders innecesarios leyendo las signals en el punto de uso.
- Mide el impacto real del bundle: el ahorro es significativo, pero tu propio código sigue siendo lo predominante.
- Prefiere
preact/preset-vitepara configurar el build correctamente desde el inicio.
Errores comunes
- Mezclar paquetes de React y Preact sin el alias de compatibilidad.
- Olvidar crear el alias de
react-dom/client, lo que rompe la nueva API de root. - Asumir que cualquier librería de React funciona sin probar la capa de compatibilidad.
- Usar signals en exceso y volver a renderizar componentes que podrían leer un signal directamente.
- Tratar a Preact como si fuera idéntico en funcionalidades a React y sorprenderse ante algún caso límite.
- Añadir Preact para reducir el tamaño y luego instalar una dependencia pesada que anula la ganancia.
Próximos pasos
Preact es la respuesta pragmática cuando el modelo de React es el adecuado, pero su tamaño no lo es. Compáralo con React y Svelte, configúralo con Vite y no descuides tus fundamentos de JavaScript. Después, intenta integrar un pequeño widget de Preact en una página HTML sencilla para comprobar lo ligero que es.