React 18中如何替换嵌套的ReactDOM.render(原React17实现)
React 18 内层嵌套渲染的迁移解决方案
在 React 18 中,createRoot 替代了原有的 ReactDOM.render,且要求每个 DOM 容器只能对应一个 React 根实例。直接替换内层 ReactDOM.render 为 createRoot 会报错,核心原因是重复创建根实例或容器元素的状态冲突,以下是针对性的解决方案:
1. 外层入口文件升级
首先按照 React 18 要求,将外层的渲染逻辑替换为 createRoot:
import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import App from './App'; const rootElement = document.getElementById('root'); const root = createRoot(rootElement); root.render( <StrictMode> <App /> </StrictMode> );
2. 内层嵌套渲染的修正
内层渲染需要避免重复创建根实例,通过 useRef 缓存已创建的根对象,确保同一容器只初始化一次根:
import { createElement, useRef } from "react"; import { createRoot } from "react-dom/client"; // 修正原代码中HTML标签闭合错误 const html = `<div id="my-id">Hi</div>`; export default function App() { // 缓存内层根实例 const innerRootRef = useRef(null); const fillMe = () => { const myDiv = document.getElementById("my-id"); if (!myDiv) return; if (innerRootRef.current) { // 根实例已存在,直接调用render更新内容 innerRootRef.current.render( createElement("h1", { className: "greeting" }, "Hello") ); } else { // 首次创建根实例并缓存 const innerRoot = createRoot(myDiv); innerRoot.render( createElement("h1", { className: "greeting" }, "Hello") ); innerRootRef.current = innerRoot; } }; return ( <div className="App"> <button onClick={fillMe}>fill me</button> <div dangerouslySetInnerHTML={{ __html: html }} /> </div> ); }
关键注意事项
- 禁止重复调用
createRoot:同一 DOM 容器只能初始化一次根实例,重复创建会触发 React 报错。 - 容器存在性校验:添加
myDiv存在判断,避免因 DOM 结构异常导致的渲染失败。 - 修正原代码错误:原 HTML 字符串中的
<div/>标签闭合错误会导致 DOM 结构异常,需改为</div>。
内容的提问来源于stack exchange,提问作者ahuegle
相关产品推荐
相关产品推荐

