React 18的createRoot与render全面对比
React 18 引入了 ReactDOM.createRoot
作为新的根 API,逐步取代了传统的 ReactDOM.render
方法。它们之间的主要区别体现在并发支持、性能优化和API设计上。以下是核心对比:
特性 | ReactDOM.createRoot (React 18+) | ReactDOM.render (React 17及更早) |
---|---|---|
并发模式 | ✅ 默认启用,支持可中断渲染、优先级调度等并发特性 | ❌ 仅支持同步渲染,阻塞主线程 |
自动批处理 | ✅ 所有状态更新(包括Promise、setTimeout)自动批量处理,减少渲染次数 | ❌ 仅在React事件回调内批处理,异步操作中可能触发多次渲染 |
返回值 | 返回根对象(如 root ),需调用 root.render() 进行渲染 | 直接返回组件实例(通常无需使用) |
API设计 | 显式创建根实例,更模块化,易于管理多根节点 | 隐式创建根,单一函数调用 |
特性支持 | 支持所有React 18新特性(如 startTransition 、流式SSR) | 仅兼容React 17及以下的行为模式 |
升级影响 | 需修改代码以适应新API,但能获得性能提升 | 旧项目无需修改,但无法享受新特性 |
🧩 关键区别详解
-
并发渲染 (Concurrent Rendering):
createRoot
启用并发模式,允许React在渲染过程中中断、暂停和恢复工作,优先处理用户交互等高优先级任务,使应用更流畅。ReactDOM.render
采用同步阻塞模式,一旦开始渲染就必须完成,可能导致界面卡顿。
-
自动批处理 (Automatic Batching):
createRoot
在所有环境(事件处理函数、Promise、setTimeout等)中自动批量处理状态更新,减少不必要的渲染。ReactDOM.render
仅在React事件回调内进行批处理,在异步代码中可能触发多次渲染。
-
API使用方式:
createRoot
需先创建根实例,再调用render
方法:import { createRoot } from 'react-dom/client'; const root = createRoot(document.getElementById('root')); root.render(<App />);
ReactDOM.render
直接调用:import ReactDOM from 'react-dom'; ReactDOM.render(<App />, document.getElementById('root'));
-
底层实现:
createRoot
创建ConcurrentRoot
类型的Fiber树,支持并发更新。ReactDOM.render
创建LegacyRoot
类型的Fiber树,仅支持同步更新。
⚙️ 代码升级示例
从 ReactDOM.render
迁移到 createRoot
:
// React 17及之前
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));// React 18+
import { createRoot } from 'react-dom/client';
import App from './App';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
💡 为何要升级?
- 性能提升:并发特性减少界面卡顿,自动批处理降低渲染次数。
- 更好的用户体验:高优先级更新(如用户输入)立即响应,非紧急更新(如数据加载)后台处理。
- 未来兼容性:React新特性仅支持
createRoot
。
⚠️ 注意事项
- 破坏性变更:升级需修改代码,旧项目可能需测试兼容性。
- 不再支持IE:React 18放弃Internet Explorer支持。
- 严格模式行为变化:开发模式下,组件可能重复挂载以检测副作用。
💡 总结:ReactDOM.createRoot
是React 18的现代化API,通过并发渲染和自动批处理大幅提升性能与用户体验。新建项目应始终使用 createRoot
,旧项目建议逐步迁移以充分利用新特性。