You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 00:48:16