ReactJS中点击按钮向父组件添加不同类型子组件的方法
React动态添加子组件实现方案
你要实现的动态追加运算符组件的效果参考:
核心思路
不要用原生JS的appendChild、getElementById这类直接操作DOM的写法,这是React开发中的反模式,会绕过React的虚拟DOM状态管理,引发渲染不一致问题。
React的UI完全由状态驱动,你只需要:
- 用一个状态数组维护当前已经添加的所有运算符块的类型
- 点击菜单按钮时,往状态数组里追加一条对应类型的记录
- 渲染时遍历状态数组,按记录的类型匹配对应的子组件渲染即可
状态更新后React会自动完成DOM的追加更新,效果和原生appendChild完全一致,且状态可控可追溯。
完整可运行代码
import React, { useState } from 'react' import Plus from "./Plus"; import Minus from "./Minus"; import And from "./And"; // 按需导入其余运算符组件 import Multiplication from "./Multiplication"; import Division from "./Division"; import Or from "./Or"; import Not from "./Not"; import Xor from "./Xor"; // 组件类型映射表:新增运算符只需要在这里加配置,不用重复写逻辑 const COMPONENT_MAP = { plus: Plus, minus: Minus, and: And, multiplication: Multiplication, division: Division, or: Or, not: Not, xor: Xor } function FunctionEditor() { // 存储已添加的运算符块,初始为空数组 const [blockList, setBlockList] = useState([]) // 统一的添加块方法,传入组件类型即可调用 const handleAddBlock = (type) => { setBlockList(prevList => [ ...prevList, { id: `${Date.now()}-${Math.random().toString(36).slice(2)}`, // 生成唯一id作为列表key type } ]) } return ( <div> <h5>Function Editor</h5> <span className='accordion-button'> <button className='btn border btn-group-sm' onClick={() => handleAddBlock('plus')}>Plus</button> <button className='btn border btn-group-sm' onClick={() => handleAddBlock('minus')}>Minus</button> <button className='btn border btn-group-sm' onClick={() => handleAddBlock('and')}>And</button> {/* 其余运算符按钮按相同格式添加即可 */} <button className='btn border btn-group-sm' onClick={() => handleAddBlock('multiplication')}>Multiplication</button> <button className='btn border btn-group-sm' onClick={() => handleAddBlock('division')}>Division</button> <button className='btn border btn-group-sm' onClick={() => handleAddBlock('or')}>Or</button> <button className='btn border btn-group-sm' onClick={() => handleAddBlock('not')}>Not</button> <button className='btn border btn-group-sm' onClick={() => handleAddBlock('xor')}>Xor</button> </span> <div id="funEditor"> {blockList.map(block => { const CurrentBlock = COMPONENT_MAP[block.type] // 需要给子组件传参(比如删除方法、配置项)直接在这里加props即可 return <CurrentBlock key={block.id} /> })} </div> </div> ); } export default FunctionEditor;
扩展说明
- 后续要加单个块删除、拖拽排序、块内参数编辑功能,只需要操作
blockList状态数组即可,比如删除功能只需要写个方法过滤掉对应id的块,调用setBlockList更新状态就会自动重新渲染。 - 每个块的唯一id必须加,这是React列表渲染的要求,能保证React正确识别每个组件的状态,避免渲染错乱。
- 用统一的组件映射表可以避免写大量
if/switch判断组件类型的冗余代码,新增自定义运算符只需要三步:导入组件、在COMPONENT_MAP加一条类型映射、加一个触发添加的按钮,不需要修改核心逻辑。
内容的提问来源于stack exchange,提问作者Bharat-Maha
相关产品推荐
相关产品推荐

