核心差异 #

一、体积对比 #

1.1 包大小 #

text
React 18.x
├── react           ~42KB (gzip ~12KB)
├── react-dom       ~130KB (gzip ~42KB)
└── 总计            ~172KB (gzip ~54KB)

Preact 10.x
├── preact          ~10KB (gzip ~3KB)
└── 总计            ~10KB (gzip ~3KB)

1.2 体积差异原因 #

方面 Preact React
合成事件
事件池
平台抽象 简化 完整
调试工具 可选 内置

二、事件系统 #

2.1 事件处理 #

jsx
// React: 合成事件
function ReactComponent() {
  const handleClick = (e) => {
    e.preventDefault();
    // e 是 SyntheticEvent
    console.log(e.nativeEvent); // 原生事件
  };
  
  return <button onClick={handleClick}>Click</button>;
}

// Preact: 原生事件
function PreactComponent() {
  const handleClick = (e) => {
    e.preventDefault();
    // e 是原生 Event
    console.log(e); // 直接是原生事件
  };
  
  return <button onClick={handleClick}>Click</button>;
}

2.2 事件差异 #

方面 Preact React
事件类型 原生 Event SyntheticEvent
事件池 有(已废弃)
e.persist() 不需要 需要(旧版本)
性能 更快 略慢

2.3 事件命名 #

jsx
// 两者相同
<button onClick={handleClick} />
<input onChange={handleChange} />
<form onSubmit={handleSubmit} />

三、DOM 属性 #

3.1 class vs className #

jsx
// React: 必须使用 className
<div className="container">Content</div>

// Preact: 两种都支持
<div className="container">Content</div>
<div class="container">Content</div>  // 推荐

3.2 for vs htmlFor #

jsx
// React: 必须使用 htmlFor
<label htmlFor="email">Email</label>

// Preact: 两种都支持
<label htmlFor="email">Email</label>
<label for="email">Email</label>  // 推荐

3.3 style 属性 #

jsx
// 两者相同
<div style={{ color: 'red', fontSize: '16px' }}>Text</div>

四、生命周期 #

4.1 类组件生命周期 #

jsx
// React 完整生命周期
class ReactComponent extends React.Component {
  constructor(props) {}
  static getDerivedStateFromProps(props, state) {}
  shouldComponentUpdate(nextProps, nextState) {}
  render() {}
  getSnapshotBeforeUpdate(prevProps, prevState) {}
  componentDidMount() {}
  componentDidUpdate(prevProps, prevState, snapshot) {}
  componentWillUnmount() {}
  static getDerivedStateFromError(error) {}
  componentDidCatch(error, info) {}
}

// Preact 简化生命周期
class PreactComponent extends Component {
  constructor(props) {}
  static getDerivedStateFromProps(props, state) {}
  shouldComponentUpdate(nextProps, nextState) {}
  render() {}
  componentDidMount() {}
  componentDidUpdate(prevProps, prevState) {}
  componentWillUnmount() {}
  static getDerivedStateFromError(error) {}
  componentDidCatch(error) {}
}

4.2 生命周期差异 #

方法 Preact React
getSnapshotBeforeUpdate
componentDidCatch info
getDerivedStateFromError

五、Hooks #

5.1 Hooks 支持 #

jsx
// 两者基本相同
import { useState, useEffect, useContext, useRef } from 'preact/hooks';
// 或
import { useState, useEffect, useContext, useRef } from 'react';

5.2 Preact 特有 Hooks #

jsx
// Preact 提供额外的 Hooks
import { 
  useErrorBoundary,  // 错误边界 Hook
  useReducer,
  useMemo,
  useCallback,
  useLayoutEffect,
  useImperativeHandle
} from 'preact/hooks';

// useErrorBoundary 示例
function ErrorBoundary({ children }) {
  const [error, resetError] = useErrorBoundary();
  
  if (error) {
    return (
      <div>
        <p>Error: {error.message}</p>
        <button onClick={resetError}>Retry</button>
      </div>
    );
  }
  
  return children;
}

六、Refs #

6.1 创建 Ref #

jsx
// React
import { createRef, useRef } from 'react';

class Component extends React.Component {
  inputRef = createRef();
  
  render() {
    return <input ref={this.inputRef} />;
  }
}

// Preact
import { createRef, useRef } from 'preact';

class Component extends Component {
  inputRef = createRef();
  
  render() {
    return <input ref={this.inputRef} />;
  }
}

6.2 forwardRef #

jsx
// 两者相同
import { forwardRef } from 'preact';
// 或
import { forwardRef } from 'react';

const Input = forwardRef((props, ref) => {
  return <input ref={ref} {...props} />;
});

七、Context #

7.1 Context API #

jsx
// React
import { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Child />
    </ThemeContext.Provider>
  );
}

// Preact
import { createContext, useContext } from 'preact';

const ThemeContext = createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Child />
    </ThemeContext.Provider>
  );
}

7.2 Context 差异 #

方面 Preact React
createContext
Provider
Consumer
useContext

八、Portals #

8.1 Portal 实现 #

jsx
// React
import { createPortal } from 'react-dom';

function Modal({ children }) {
  return createPortal(
    <div class="modal">{children}</div>,
    document.body
  );
}

// Preact
import { createPortal } from 'preact';

function Modal({ children }) {
  return createPortal(
    <div class="modal">{children}</div>,
    document.body
  );
}

九、错误边界 #

9.1 类组件错误边界 #

jsx
// React
class ErrorBoundary extends React.Component {
  state = { hasError: false };
  
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  
  componentDidCatch(error, errorInfo) {
    console.log(errorInfo.componentStack);
  }
  
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

// Preact
class ErrorBoundary extends Component {
  state = { hasError: false };
  
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  
  componentDidCatch(error) {
    console.log(error);
  }
  
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

9.2 函数组件错误边界 #

jsx
// Preact 特有
import { useErrorBoundary } from 'preact/hooks';

function ErrorBoundary({ children }) {
  const [error, resetError] = useErrorBoundary();
  
  if (error) {
    return (
      <div>
        <p>Error: {error.message}</p>
        <button onClick={resetError}>Retry</button>
      </div>
    );
  }
  
  return children;
}

十、性能对比 #

10.1 基准测试 #

text
操作          Preact      React
首次渲染      ~5ms        ~15ms
更新          ~2ms        ~5ms
内存占用      ~1MB        ~4MB

10.2 性能差异原因 #

方面 Preact React
事件系统 原生 合成
虚拟DOM 简化 完整
Diff算法 优化 标准
包体积

十一、生态系统 #

11.1 官方库 #

Preact React
路由 preact-router react-router
状态 signals redux/zustand
SSR preact-render-to-string next.js
CLI preact-cli create-react-app

11.2 兼容性 #

jsx
// 使用 preact/compat 兼容 React 库
import { render } from 'preact';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';

function App() {
  return (
    <Provider store={store}>
      <BrowserRouter>
        <Main />
      </BrowserRouter>
    </Provider>
  );
}

十二、选择建议 #

12.1 选择 Preact #

  • 追求极致性能
  • 包体积敏感
  • 移动端应用
  • 渐进式增强
  • 微前端子应用

12.2 选择 React #

  • 大型企业应用
  • 需要完整生态
  • 团队熟悉 React
  • 需要社区支持
  • 复杂项目需求

十三、总结 #

方面 Preact React
体积 3KB 54KB
事件 原生 合成
性能 更快
生态 兼容 完整
学习 简单 中等

核心差异:

  • Preact 更轻量、更快
  • React 生态更完善
  • 通过 compat 可兼容 React 库
  • 根据项目需求选择
最后更新:2026-03-28