如何通过DOM操作将React组件追加到指定HTML元素中
问题根源
你的代码存在核心逻辑错误:JSX 语法编写的 React 元素(包括<button><BsIcons.BsClockHistory /></button>这类带React图标组件的节点)本质是普通JavaScript对象,不是浏览器原生DOM节点,无法直接作为参数传入原生appendChild()方法——原生DOM API 仅能操作真实的Node类型实例,无法识别React元素对象。
此外你的代码还存在listEl变量未声明、节点拼接顺序混乱的问题。
正确实现方案
React组件(包括react-icons提供的图标组件)不能直接用原生DOM操作插入,必须通过React自身的渲染逻辑挂载到真实DOM节点上,以下是适配你场景的可落地方案:
方案1:统一渲染逻辑(推荐,避免混用原生API和JSX)
不要一半用document.createElement生成节点、一半写JSX,直接通过React的渲染API把带图标的按钮挂载到目标容器即可,适配React 18+版本的代码如下:
import { BsClockHistory } from 'react-icons/bs'; import { createRoot } from 'react-dom/client'; // 获取外层容器 const uList = document.getElementById("uList"); // 创建列表项节点 const listEl = document.createElement("li"); // 为列表项创建React渲染根节点,渲染带图标的按钮 const listRoot = createRoot(listEl); listRoot.render( <button> <BsClockHistory /> New Button </button> ); // 最终把列表项挂到ul容器上 uList.appendChild(listEl);
如果你使用的是React 17及更早版本,替换成旧版渲染API即可:
import ReactDOM from 'react-dom'; const listEl = document.createElement("li"); ReactDOM.render( <button><BsClockHistory /> New Button</button>, listEl );
方案2:拆分原生节点和React组件渲染
如果段落文本等其他节点必须用原生DOM生成,仅单独渲染带图标的按钮即可:
import { BsClockHistory } from 'react-icons/bs'; import { createRoot } from 'react-dom/client'; const para = document.createElement("p"); const node = document.createTextNode("New Button"); const uList = document.getElementById("uList"); const listEl = document.createElement("li"); // 创建空的原生按钮节点作为容器 const btnNode = document.createElement("button"); // 把React图标组件渲染到按钮容器内 const btnRoot = createRoot(btnNode); btnRoot.render(<BsClockHistory />); // 按顺序拼接所有节点 para.appendChild(node); listEl.appendChild(btnNode); listEl.appendChild(para); uList.appendChild(listEl);
注意事项
- 禁止直接将JSX元素传入原生appendChild方法:React组件(包括图标)自带事件绑定、状态更新逻辑,脱离React渲染流程强行挂载会出现事件失效、内存泄漏、状态不同步等不可预期问题。
- 如果这段逻辑写在React函数/类组件内部,完全不需要混用原生DOM操作,直接在组件返回的JSX中书写
<button><BsClockHistory /> New Button</button>即可,React会自动完成所有渲染工作。
内容的提问来源于stack exchange,提问作者SlothOnCrack
相关产品推荐
相关产品推荐

