React新旧版本差异:createRoot渲染后canvas获取为null问题
问题原因及解决方案
核心差异:同步 vs 异步渲染
ReactDOM.render是同步渲染:调用后会立即完成DOM的挂载与渲染,所以在它执行后直接查询canvas元素,能拿到已挂载的DOM节点。createRoot启用并发异步渲染(React 18+核心特性):渲染任务会被React调度,可能拆分或延后执行,不会阻塞主线程。如果在调用createRoot().render(<App />)后立刻查询DOM,此时React大概率还没完成canvas的挂载,因此返回null。
适配旧代码的问题
早期Excalidraw代码基于React同步渲染逻辑编写,可能存在同步依赖DOM挂载的逻辑(比如组件外部直接查询DOM、或在组件生命周期早期未等待渲染完成就获取元素)。createRoot的异步特性打破了这种同步依赖,导致获取DOM时元素未就绪。
正确的DOM获取方式
要在createRoot模式下正常获取canvas,需调整为React推荐的异步方式:
- 使用Ref机制:在组件内定义
const canvasRef = useRef(null),给canvas元素添加ref={canvasRef},然后在useEffect钩子中访问canvasRef.current——useEffect会在DOM更新完成后执行,此时能拿到已挂载的canvas。 - 依赖生命周期钩子:如果是组件外部查询DOM,必须确保等待React完成渲染,比如将查询逻辑放在组件的
useEffect中,而非直接在render调用后同步执行。
React官方说明核心要点
React 18文档明确了两者的关键区别:
ReactDOM.render属于旧版同步API,在React 18中使用会进入兼容模式,不启用并发特性。createRoot是新版渲染入口,默认启用并发渲染,渲染过程异步,不能假设调用render后DOM会立即更新。- 所有依赖同步获取DOM的逻辑都需要调整为React钩子或生命周期方法,避免直接在render调用后同步查询DOM。
内容的提问来源于stack exchange,提问作者Deni Streltsov
相关产品推荐
相关产品推荐

