React运行时向父组件动态添加子组件报appendChild不存在错误如何解决
问题原因
你当前的写法混淆了React声明式渲染逻辑和原生DOM操作逻辑:
- React组件实例不是真实DOM节点,没有
appendChild方法,直接new组件类、调用DOM方法的操作不符合React的设计范式 - React的UI更新完全由状态驱动,要修改组件内容只需要修改对应状态,框架会自动完成重渲染
修复步骤
1. 改造App组件,新增状态控制CenterSpace渲染内容
App是所有组件的公共父节点,我们在这里定义控制中部区域内容的状态,以及修改状态的方法,向下传递给需要的组件:
import React from 'react'; import './App.css'; // 引入需要渲染到中部的组件 import Header from './components/Header'; import Footer from './components/Footer'; import LeftSideSpace from './components/LeftSideSpace'; import RightSideSpace from './components/RightSideSpace'; import CenterSpace from './components/CenterSpace'; import MainMenu from './components/complications/MainMenu'; import HomeLists from './components/complications/HomeLists'; // 其他要渲染的组件比如Blogs、AboutMe也提前引入 class App extends React.Component { // 新增状态存储当前中部要渲染的内容 state = { centerContent: null } // 提供修改中部内容的方法 setCenterContent = (content) => { this.setState({ centerContent: content }) } render() { return ( <div className="App"> <Header title='My Blog'/> {/* 把修改状态的方法传给菜单组件 */} <MainMenu setCenterContent={this.setCenterContent} /> <LeftSideSpace/> {/* 把状态作为children传给CenterSpace */} <CenterSpace> {this.state.centerContent} </CenterSpace> <RightSideSpace/> <Footer title='Welcome! This is my Blog site'/> </div> ); } } export default App;
2. 改造MainMenu组件,用传下来的方法更新内容
删除原来直接操作组件实例的逻辑,点击按钮时直接把对应组件传给状态更新方法即可:
import React from 'react'; import PropTypes from 'prop-types' import HomeLists from './HomeLists' // 引入其他要切换的组件 class MainMenu extends React.Component { render() { return ( <div className="Site.MainMenu"> <button onClick={() => this.props.setCenterContent(<HomeLists />)}>Home</button> <button onClick={() => this.props.setCenterContent(<Blogs />)}>Blogs</button> <button onClick={() => this.props.setCenterContent(<AboutMe />)}>About Me</button> </div> ); } } MainMenu.propTypes = { setCenterContent: PropTypes.func.isRequired, } export default MainMenu
3. 修复HomeLists组件的错误逻辑
- 浏览器环境没有Node.js的
fs模块,无法直接读取本地文件,建议把JSON文件放到项目的public文件夹下,用fetch异步请求,或者提前把JSON导入到组件中 - 不要手动创建DOM节点,React的渲染逻辑统一写到
render的返回值中,用数组遍历生成JSX即可:
import React from 'react'; import PropTypes from 'prop-types' // 示例:提前导入所有JSON文件(也可以用fetch动态请求) import blog1 from '../data/blog1.json' import blog2 from '../data/blog2.json' const blogList = [blog1, blog2] class HomeLists extends React.Component { render() { return ( <div className="Site.HomeLists"> <div id="Site.HomeLists.Content"> {/* 遍历博客数据生成对应的DOM结构 */} {blogList.map((json, index) => ( <div key={index}> <h3>{json.title}</h3> <p>{json.blog.content[0].value}</p> </div> ))} </div> </div> ); } } HomeLists.defaultProps = { title: 'Personal Blogger\'s site' } HomeLists.propTypes = { title: PropTypes.string.isRequired } export default HomeLists
额外优化建议:CenterSpace组件中自定义的
<centerspace>标签建议改成标准<div>,避免浏览器兼容性问题。
内容的提问来源于stack exchange,提问作者kishoredbn
相关产品推荐
相关产品推荐

