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

React JS中如何动态添加嵌套子数组输入字段 单section支持多视频行

实现方案

你需要新增针对单个section添加视频输入对的处理逻辑,同时调整JSX渲染结构新增对应操作按钮即可,具体修改如下:

1. 新增视频操作处理函数

在组件中新增两个函数(删除单组视频为可选优化,满足至少保留1组视频的常用需求):

// 给指定section新增一组视频输入
const handleAddVideoField = (sectionIndex) => {
  const newSectionFields = [...sectionFields];
  newSectionFields[sectionIndex].videoContents.push({
    videoName: '',
    videoUrl: ''
  });
  setSectionFields(newSectionFields);
};

// 可选:删除指定section下的某组视频输入,至少保留1组
const handleRemoveVideoField = (sectionIndex, videoIndex) => {
  const newSectionFields = [...sectionFields];
  newSectionFields[sectionIndex].videoContents.splice(videoIndex, 1);
  // 防止视频组被全部删除
  if (newSectionFields[sectionIndex].videoContents.length === 0) {
    newSectionFields[sectionIndex].videoContents.push({
      videoName: '',
      videoUrl: ''
    });
  }
  setSectionFields(newSectionFields);
};

2. 调整JSX渲染结构

在视频输入对的位置新增操作按钮,同时你原有代码中函数名拼写Chang应为Change,同步修正即可:
修改后的视频渲染部分代码:

{inputField?.videoContents?.map((v, i) => (
  <div key={i} style={{ display: 'flex', alignItems: 'center', marginLeft: '24px' }}>
    <TextField
      name="videoName"
      label="Enter Video Name"
      variant="filled"
      value={v.videoName}
      onChange={event => handleChangeVideoInput(index, i, event)}
    />
    <TextField
      name="videoUrl"
      label="Enter Video Url"
      variant="filled"
      value={v.videoUrl}
      onChange={event => handleChangeVideoInput(index, i, event)}
    />
    {/* 当前section下新增视频组的加号按钮 */}
    <IconButton onClick={() => handleAddVideoField(index)}>
      <AddIcon />
    </IconButton>
    {/* 可选:删除当前视频组的减号按钮,仅当视频组数量大于1时显示 */}
    {inputField.videoContents.length > 1 && (
      <IconButton onClick={() => handleRemoveVideoField(index, i)}>
        <RemoveIcon />
      </IconButton>
    )}
  </div>
))}

完整修改后代码

const useStyles = makeStyles((theme) => ({
  root: {
    '& .MuiTextField-root': {
      margin: theme.spacing(1)
    },
  },
  button: {
    margin: theme.spacing(1)
  }
}))

function CreateCourse() {
  const classes = useStyles();
  const [sectionFields, setSectionFields] = useState([{
    sectionName: '',
    overview: '',
    videoContents: [{
      videoName: '', videoUrl: ''
    }]
  }])

  // 修正原拼写错误 Chang => Change
  function handleChangeInput(index, event) {
    const values = [...sectionFields];
    values[index][event.target.name] = event.target.value;
    setSectionFields(values);
  }

  // 修正原拼写错误 Chang => Change
  function handleChangeVideoInput(index, i, event) {
    const values = [...sectionFields];
    values[index].videoContents[i][event.target.name] = event.target.value;
    setSectionFields(values);
  }

  const handleSubmit = (event) => {
    event.preventDefault();
    console.log("Input Field ", sectionFields)
  }

  const handleRemoveFields = (index) => {
    const values = [...sectionFields];
    values.splice(index, 1)
    setSectionFields(values)
  }

  const handleAddFields = () => {
    setSectionFields([...sectionFields, {
      sectionName: '',
      overview: '',
      videoContents: [{videoName: '', videoUrl: ''}]
    }])
  }

  // 给指定section新增一组视频输入
  const handleAddVideoField = (sectionIndex) => {
    const newSectionFields = [...sectionFields];
    newSectionFields[sectionIndex].videoContents.push({
      videoName: '',
      videoUrl: ''
    });
    setSectionFields(newSectionFields);
  };

  // 可选:删除指定section下的某组视频输入,至少保留1组
  const handleRemoveVideoField = (sectionIndex, videoIndex) => {
    const newSectionFields = [...sectionFields];
    newSectionFields[sectionIndex].videoContents.splice(videoIndex, 1);
    // 防止视频组被全部删除
    if (newSectionFields[sectionIndex].videoContents.length === 0) {
      newSectionFields[sectionIndex].videoContents.push({
        videoName: '',
        videoUrl: ''
      });
    }
    setSectionFields(newSectionFields);
  };

  return (
    <div className='container mb-5'>
      <Container>
        <h1>Add New Member</h1>
        <form className={classes.root} onSubmit={handleSubmit}>
          {sectionFields.map((inputField, index) => (
            <div key={index}>
              <TextField
                name="sectionName"
                label="Section Name"
                variant="filled"
                value={inputField?.sectionName}
                onChange={event => handleChangeInput(index, event)}
              />
              <TextField
                name="overview"
                label="Section Overview"
                variant="filled"
                value={inputField?.overview}
                onChange={event => handleChangeInput(index, event)}
              />

              <IconButton onClick={() => handleRemoveFields(index)}>
                <RemoveIcon/>
              </IconButton>
              <IconButton onClick={handleAddFields}>
                <AddIcon/>
              </IconButton>

              {inputField?.videoContents?.map((v, i) => (
                <div key={i} style={{ display: 'flex', alignItems: 'center', marginLeft: '24px', marginTop: '8px' }}>
                  <TextField
                    name="videoName"
                    label="Enter Video Name"
                    variant="filled"
                    value={v.videoName}
                    onChange={event => handleChangeVideoInput(index, i, event)}
                  />
                  <TextField
                    name="videoUrl"
                    label="Enter Video Url"
                    variant="filled"
                    value={v.videoUrl}
                    onChange={event => handleChangeVideoInput(index, i, event)}
                  />
                  {/* 当前section下新增视频组的加号按钮 */}
                  <IconButton onClick={() => handleAddVideoField(index)}>
                    <AddIcon />
                  </IconButton>
                  {/* 可选:删除当前视频组的减号按钮,仅当视频组数量大于1时显示 */}
                  {inputField.videoContents.length > 1 && (
                    <IconButton onClick={() => handleRemoveVideoField(index, i)}>
                      <RemoveIcon />
                    </IconButton>
                  )}
                </div>
              ))}
            </div>
          ))}
          <Button
            className={classes.button}
            variant='contained'
            color='primary'
            type='submit'
            endIcon={<Icon/>}
            onClick={handleSubmit}
          >
            SEND
          </Button>
        </form>
      </Container>
    </div>
  );
}
export default CreateCourse;

修改后原section旁的加号按钮功能保持不变,点击仍新增完整section行;每组视频输入旁的加号点击后只会在当前section下新增一组视频输入对,符合需求。

内容的提问来源于stack exchange,提问作者Partho

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 07:45:00