React createPortal未插入子元素到容器且不触发UI渲染问题
问题根因
你对ReactDOM.createPortal的用法存在本质错误,这也是点击后没有内容渲染的核心原因:
createPortal本身只返回一个特殊格式的React元素,它不会主动执行DOM挂载操作。你在add事件回调里单独调用这个API,生成的React元素根本没有进入React的渲染流程,和声明了一个变量没使用是一个效果,自然不会在页面上产出任何DOM。- 你的实现思路是命令式操作DOM,完全不符合React状态驱动渲染的核心逻辑。
createPortal从来不是用来替代appendChild做动态节点插入的命令式API。 - 额外提一句:你的待办场景里li本身就是ul的子节点,根本不需要用到portal,这个API的设计目标是把组件渲染到当前父组件DOM树之外的节点上(比如全局弹窗、悬浮提示这类需要脱离父容器overflow、z-index限制的场景)。
正确实现
标准React写法(不需要portal)
所有UI数据存在组件state中,点击按钮时只需要更新state,React会自动触发重渲染、更新DOM,不要手动操作DOM插入节点:
import React from 'react' class App extends React.Component { // 初始化待办列表状态 state = { todoList: [] } // 用箭头函数绑定this,避免回调里this指向异常 add = () => { const inputEl = document.getElementById("textInput"); const textVal = inputEl.value.trim(); if (!textVal) return; // 更新状态触发重渲染 this.setState({ todoList: [...this.state.todoList, textVal] }) // 清空输入框 inputEl.value = ''; } render(){ return ( <div> To Do list: <ul id='ul'> {/* 遍历状态渲染所有li节点 */} {this.state.todoList.map((todo, idx) => <li key={idx}>{todo}</li>)} </ul> <input type="text" id="textInput" /> <input type="button" value="Add" onClick={this.add}/> </div> ); } } export default App
如果要练习createPortal的正确用法
记住:createPortal生成的节点必须写在render的返回内容里,跟随组件的渲染流程挂载,它只是改变了节点最终挂载的DOM位置,事件冒泡、React生命周期逻辑依然和正常渲染的节点完全一致:
import React from 'react' import ReactDOM from 'react-dom'; class App extends React.Component { state = { todoList: [] } add = () => { const inputEl = document.getElementById("textInput"); const textVal = inputEl.value.trim(); if (!textVal) return; this.setState({ todoList: [...this.state.todoList, textVal] }) inputEl.value = ''; } render(){ return ( <div> To Do list: {/* 遍历列表时返回portal节点,会把li挂载到指定的外部DOM节点下 */} {this.state.todoList.map((todo, idx) => { // 这里可以把li渲染到页面任意已存在的DOM节点上,哪怕在当前组件DOM树外面 return ReactDOM.createPortal( <li key={idx}>{todo}</li>, document.getElementById('ul') ) })} <input type="text" id="textInput" /> <input type="button" value="Add" onClick={this.add}/> </div> ); } } export default App
关键注意点
- 永远不要在事件回调里单独调用
createPortal指望它能直接渲染内容,它的返回值必须作为组件渲染输出的一部分才能生效 - React下所有UI更新都要通过修改state驱动,不要把React API当成原生DOM操作方法用
- portal只适合需要跳出父DOM容器限制的场景,普通父子组件渲染不需要使用这个API
内容的提问来源于stack exchange,提问作者Youssef Mohamed
相关产品推荐
相关产品推荐

