React 18中如何通过代码方式创建Modal组件?
React 18 替代 ReactDOM.render 实现动态创建 Modal 的方案
问题背景
在 React 17 中通过调用函数实现了动态创建 Modal 的功能,只需调用函数就能生成新的 Modal 实例,且组件可自行管理状态、支持多实例同时存在。但 React 18 中 ReactDOM.render 被弃用后,原有功能无法正常运行,需要找到能在指定 DOM 元素中渲染简单组件的替代方案。
解决方案
React 18 中可以用 createRoot API 替代 ReactDOM.render,核心思路是为每个动态创建的 Modal 生成独立的 DOM 容器,避免多实例冲突,同时在 Modal 关闭时自动卸载根实例并清理 DOM,防止内存泄漏。
修改后的代码实现
1. 全局容器(index.js)
仅需将原有的 ReactDOM.render 替换为 React 18 的 createRoot 写法,保留 modal-container:
import React from 'react' import ReactDOM from 'react-dom/client' import './index.scss' import App from './App.jsx' const root = ReactDOM.createRoot(document.getElementById('root')) root.render( <React.StrictMode> <div id="modal-container"></div> <App /> </React.StrictMode> )
2. Modal 组件(Modal/Modal.jsx)
新增 onClose 回调,用于在关闭时通知外部执行卸载逻辑:
import { useState } from 'react' import './Modal.scss' const Modal = ({ content, onClose }) => { const [isOpen, setIsOpen] = useState(true) const handleClose = () => { setIsOpen(false) onClose() } if (isOpen) { return ( <> <div className="modal-background" onClick={handleClose} /> <div className="modal-content"> {content} </div> <button onClick={handleClose} className="close-button">Close</button> </> ) } else return null } export default Modal
3. 创建 Modal 的工具函数(Modal/index.js)
使用 createRoot 替代原有的 render,为每个 Modal 创建独立 DOM 容器:
import { createRoot } from "react-dom/client" import Modal from "./Modal" const createModal = (content) => { // 创建独立的 DOM 元素 const modalElement = document.createElement('div') // 将元素挂载到全局 Modal 容器中 document.getElementById("modal-container").appendChild(modalElement) // 创建 React 根实例并渲染 Modal const root = createRoot(modalElement) root.render( <Modal content={content} onClose={() => { // 卸载 React 根实例 root.unmount() // 移除对应的 DOM 元素 modalElement.remove() }} /> ) } export default createModal
4. 调用示例(app.jsx)
无需改动,保持原有的便捷调用方式:
<button onClick={() => createModal(<h1>I'm a component inside a modal</h1>)}>Open Modal</button>
说明
- 每个动态生成的 Modal 都拥有独立的 React 根实例和 DOM 元素,多实例之间互不干扰
- 关闭 Modal 时会自动完成根实例卸载和 DOM 清理,避免内存泄漏
- 完全保留了原有的“调用函数即创建 Modal”的便捷性
内容的提问来源于stack exchange,提问作者DoRyu Dracken
相关产品推荐
相关产品推荐

