兼容模式 #
一、兼容模式概述 #
1.1 什么是 preact/compat #
preact/compat 是 Preact 提供的兼容层,允许在 Preact 中使用 React 生态系统。
text
React 代码 → preact/compat → Preact 运行时
1.2 兼容范围 #
| 功能 | 支持 |
|---|---|
| React API | ✅ |
| Hooks | ✅ |
| Context | ✅ |
| Refs | ✅ |
| Portals | ✅ |
| 合成事件 | 部分 |
二、配置兼容模式 #
2.1 安装 #
bash
npm install preact
2.2 Vite 配置 #
javascript
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/test-utils': 'preact/test-utils',
'react/jsx-runtime': 'preact/jsx-runtime',
'react/jsx-dev-runtime': 'preact/jsx-dev-runtime'
}
}
});
2.3 Webpack 配置 #
javascript
module.exports = {
resolve: {
alias: {
'react': 'preact/compat',
'react-dom': 'preact/compat',
'react-dom/test-utils': 'preact/test-utils'
}
}
};
2.4 Rollup 配置 #
javascript
import alias from '@rollup/plugin-alias';
export default {
plugins: [
alias({
entries: [
{ find: 'react', replacement: 'preact/compat' },
{ find: 'react-dom', replacement: 'preact/compat' },
{ find: 'react-dom/test-utils', replacement: 'preact/test-utils' }
]
})
]
};
2.5 TypeScript 配置 #
json
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact",
"baseUrl": ".",
"paths": {
"react": ["node_modules/preact/compat"],
"react-dom": ["node_modules/preact/compat"],
"react-dom/test-utils": ["node_modules/preact/test-utils"]
}
}
}
三、兼容的 React 库 #
3.1 React Router #
jsx
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
3.2 Redux #
jsx
import { Provider, useSelector, useDispatch } from 'react-redux';
import { configureStore, createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: state => { state.value += 1; },
decrement: state => { state.value -= 1; }
}
});
const store = configureStore({
reducer: counterSlice.reducer
});
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
function Counter() {
const count = useSelector(state => state.value);
const dispatch = useDispatch();
return (
<div>
<p>{count}</p>
<button onClick={() => dispatch(counterSlice.actions.increment())}>+</button>
<button onClick={() => dispatch(counterSlice.actions.decrement())}>-</button>
</div>
);
}
3.3 React Query #
jsx
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<Users />
</QueryClientProvider>
);
}
function Users() {
const { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(res => res.json())
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error</p>;
return (
<ul>
{data.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
3.4 Framer Motion #
jsx
import { motion } from 'framer-motion';
function AnimatedComponent() {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.5 }}
>
Animated content
</motion.div>
);
}
3.5 React Hook Form #
jsx
import { useForm } from 'react-hook-form';
function MyForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email', { required: true })} />
{errors.email && <span>Email is required</span>}
<input type="password" {...register('password', { minLength: 6 })} />
{errors.password && <span>Min 6 characters</span>}
<button type="submit">Submit</button>
</form>
);
}
四、兼容 API #
4.1 核心组件 #
jsx
import {
Component,
PureComponent,
memo,
forwardRef,
createContext,
Fragment,
StrictMode,
Suspense,
lazy
} from 'preact/compat';
// 使用方式与 React 相同
const MemoComponent = memo(function Component({ data }) {
return <div>{data}</div>;
});
const Input = forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
const ThemeContext = createContext('light');
const LazyComponent = lazy(() => import('./HeavyComponent'));
4.2 Hooks #
jsx
import {
useState,
useEffect,
useContext,
useReducer,
useCallback,
useMemo,
useRef,
useImperativeHandle,
useLayoutEffect,
useDebugValue
} from 'preact/compat';
// 使用方式与 React 相同
function Counter() {
const [count, setCount] = useState(0);
const prevCount = useRef(count);
useEffect(() => {
prevCount.current = count;
}, [count]);
return <div>{count}</div>;
}
4.3 渲染 API #
jsx
import { render, createRoot, hydrate, createPortal } from 'preact/compat';
// React 18 方式
const root = createRoot(document.getElementById('root'));
root.render(<App />);
// 传统方式
render(<App />, document.getElementById('root'));
// SSR 水合
hydrate(<App />, document.getElementById('root'));
// Portal
function Modal({ children }) {
return createPortal(
<div class="modal">{children}</div>,
document.body
);
}
五、不兼容的功能 #
5.1 合成事件 #
jsx
// React 合成事件特有方法
e.isPropagationStopped();
e.isDefaultPrevented();
e.isPersistent();
e.persist();
e.nativeEvent;
// Preact 使用原生事件
// 这些方法不可用
5.2 生命周期 #
jsx
// React 支持
getSnapshotBeforeUpdate(prevProps, prevState) {}
// Preact 不支持
// 使用 useLayoutEffect 替代
5.3 内部 API #
jsx
// React 内部 API(不推荐使用)
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
// Preact 不支持
六、性能考虑 #
6.1 包体积 #
text
Preact + compat
├── preact ~10KB
├── preact/compat ~2KB
└── 总计 ~12KB
vs React
├── react ~42KB
├── react-dom ~130KB
└── 总计 ~172KB
6.2 运行时性能 #
jsx
// compat 模式性能略低于纯 Preact
// 但仍优于 React
// 推荐逐步迁移到纯 Preact API
七、调试 #
7.1 DevTools #
jsx
// 安装 Preact DevTools
import 'preact/debug';
// 或使用 React DevTools(兼容模式)
import 'preact/devtools';
7.2 错误信息 #
jsx
// 开发模式下启用详细错误
if (process.env.NODE_ENV === 'development') {
require('preact/debug');
}
八、最佳实践 #
8.1 渐进迁移 #
jsx
// 第一阶段:使用 compat 兼容
import { useState } from 'react'; // 通过别名
// 第二阶段:逐步替换
import { useState } from 'preact/hooks';
// 第三阶段:移除 compat
import { useState } from 'preact/hooks';
8.2 选择性使用 #
jsx
// 只对需要的库使用 compat
import { render } from 'preact'; // 纯 Preact
import { Provider } from 'react-redux'; // 需要 compat
九、总结 #
| 要点 | 说明 |
|---|---|
| 配置 | 设置别名 |
| 兼容 | 大部分 React 库 |
| 差异 | 合成事件、部分生命周期 |
| 性能 | 略低于纯 Preact |
核心原则:
- 使用别名实现兼容
- 测试第三方库兼容性
- 渐进迁移到纯 Preact
- 注意性能影响
最后更新:2026-03-28