Preact
React 的轻量替代,API 与 React 完全兼容,压缩后仅 ~3KB(React ~45KB)。去掉了合成事件系统、PropTypes 等非核心部分,保留 Virtual DOM + Hooks 核心。
与 React 的关系
| 对比项 | React | Preact |
|---|---|---|
| 包体积(gzip) | ~45KB | ~3KB |
| API 兼容性 | — | 通过 preact/compat 100% 兼容 |
| 事件系统 | 合成事件(SyntheticEvent) | 原生 DOM 事件 |
| 渲染器 | react-dom | preact 内置 |
| Concurrent Mode | 支持 | 不支持 |
| Signals | 不内置 | @preact/signals(官方) |
快速上手
npm create preact@latestimport { render } from "preact"
import { useState } from "preact/hooks"
function App() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}
render(<App />, document.getElementById("app"))Hooks 从 preact/hooks 导入,与 React 用法完全一致。
preact/compat 兼容层
将已有 React 项目迁移到 Preact,只需别名配置,无需改代码:
// vite.config.js
export default {
resolve: {
alias: {
"react": "preact/compat",
"react-dom": "preact/compat",
"react/jsx-runtime": "preact/jsx-runtime",
}
}
}Signals(响应式原语)
Preact 官方推出的细粒度响应式方案,比 useState 性能更高——仅更新实际用到该 signal 的 DOM 节点,不触发组件重渲染。
import { signal, computed } from "@preact/signals"
const count = signal(0)
const double = computed(() => count.value * 2)
function Counter() {
return (
<div>
<p>count: {count}</p>
<p>double: {double}</p>
<button onClick={() => count.value++}>+1</button>
</div>
)
}也可在 React 项目中通过 @preact/signals-react 使用。
服务端渲染(SSR)
import { render } from "preact-render-to-string"
import { App } from "./App.jsx"
const html = render(<App />)Quartz 即用此方式将组件渲染为静态 HTML,组件无运行时水合。
Hooks 差异速查
// React
import { useState, useEffect, useRef } from "react"
// Preact(同名,不同包路径)
import { useState, useEffect, useRef } from "preact/hooks"useMemo、useCallback、useContext、useReducer 用法与 React 完全相同。
适用场景
| 场景 | 推荐 |
|---|---|
| 性能敏感的小型 Widget / Web Component | ✅ 首选 |
| 已有 React 项目降包体积 | ✅ preact/compat 无缝迁移 |
| 静态站点生成(SSG/SSR) | ✅ Quartz、Astro 均内置 |
| 需要 Concurrent Mode / Server Components | ❌ 用 React |
| 深度依赖 Next.js 生态 | ❌ 用 React |
→ React(完整版) → Vue