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

React类组件中如何从动态表单获取数据并更新state输出JSON数组

问题核心错误点
  • handleChange逻辑错误:没有定位到video_data/subvideo_data数组的对应索引项,直接把表单值写到了state根目录,没有存进对应的表单对象里
  • 表单value绑定路径错误:动态生成的表单值都存在数组对应项中,原有代码直接从state根路径取不存在的字段,导致输入时不会同步显示
  • 文件输入框错误绑定value:文件输入框的value是只读属性,强制绑定会抛出异常,需要单独处理

修改后完整代码
import React from "react";
import { Button, Container, Form } from "react-bootstrap";
import { FaTrashAlt } from "react-icons/fa";

class Forms extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      video_data: [
        {
          _id: "",
          book_All_details: "",
          number_of_chapters: "",
          chapter: 1,
          video_title: "",
          description: "",
          video_url: null, // 文件类型存File对象,不要存空字符串
          video_image: null,
          releaseDate: "",
          subvideo_data: [
            {
              _id: "",
              subchapterid: "",
              subchapter: 1,
              subvideo_title: "",
              subdescription: "",
              subvideo_url: null,
              subvideo_image: null,
              subreleaseDate: "",
            },
          ],
        },
      ],
    };
    // 统一绑定this,不用每次render都bind
    this.handleChange = this.handleChange.bind(this);
    this.addTClick = this.addTClick.bind(this);
    this.removeTClick = this.removeTClick.bind(this);
    this.addFTClick = this.addFTClick.bind(this);
    this.removeFormFields = this.removeFormFields.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // 改造后的handleChange,接收章节索引i、子章节索引idx(非必填)、事件对象e
  handleChange(i, idx, e) {
    const { name, value, type, files } = e.target;
    const video_data = [...this.state.video_data];
    // 子章节字段更新
    if (idx !== undefined) {
      const subvideo_data = [...video_data[i].subvideo_data];
      subvideo_data[idx][name] = type === 'file' ? files[0] : value;
      video_data[i].subvideo_data = subvideo_data;
    } else {
      // 父章节字段更新
      video_data[i][name] = type === 'file' ? files[0] : value;
    }
    this.setState({ video_data });
  }

  // 添加子章节
  addTClick(i) {
    const video_data = [...this.state.video_data];
    video_data[i].subvideo_data.push({
      subvideo_title: "",
      subdescription: "",
      subvideo_url: null,
      subvideo_image: "",
    });
    this.setState({ video_data });
  }

  // 删除子章节
  removeTClick(i, idx) {
    const video_data = [...this.state.video_data];
    video_data[i].subvideo_data.splice(idx, 1);
    this.setState({ video_data });
  }

  // 添加父章节
  addFTClick() {
    const video_data = [...this.state.video_data];
    video_data.push({
      number_of_chapters: "",
      chapter: video_data.length + 1,
      video_title: "",
      description: "",
      video_url: null,
      video_image: null,
      subvideo_data: [
        { subvideo_title: "", subdescription: "", subvideo_url: null, subvideo_image: null },
      ],
    });
    this.setState({ video_data });
  }

  // 删除父章节
  removeFormFields(i) {
    const video_data = [...this.state.video_data];
    video_data.splice(i, 1);
    this.setState({ video_data });
  }

  // 提交表单获取JSON数组
  handleSubmit(e) {
    e.preventDefault();
    // 这里的video_data就是你要的JSON数组格式数据
    const formData = this.state.video_data;
    console.log("提交的表单数据:", JSON.stringify(formData));
    // 后续请求逻辑写在这里
  }

  render() {
    return (
      <Container>
        <form onSubmit={this.handleSubmit}>
          {this.state.video_data.map((video_datas, i) => (
            <div key={i} className="container" style={{ background: "aqua", margin: '10px 0' }}>
              <div className="form-group col-sm-4">
                <label>Enter Chapter Name:</label>
                <input
                  type="text"
                  name="number_of_chapters"
                  onChange={(e) => this.handleChange(i, undefined, e)}
                  value={video_datas.number_of_chapters}
                  className="form-control"
                  placeholder="title"
                />
              </div>
              <div className="row">
                <div className="form-group col-sm-6">
                  <label>Title:</label>
                  <input
                    type="text"
                    onChange={(e) => this.handleChange(i, undefined, e)}
                    value={video_datas.video_title}
                    name="video_title"
                    className="form-control"
                    placeholder="title"
                  />
                </div>
                <div className="form-group col-sm-6">
                  <label>Description:</label>
                  <input
                    type="text"
                    onChange={(e) => this.handleChange(i, undefined, e)}
                    value={video_datas.description}
                    name="description"
                    className="form-control"
                    placeholder="authors"
                  />
                </div>
              </div>
              <div className="form-group">
                <label>Thambnail image:</label>
                <input
                  onChange={(e) => this.handleChange(i, undefined, e)}
                  name="video_image"
                  type="file"
                  className="form-control"
                />
              </div>
              <div className="form-group">
                <label>Upload Video:</label>
                <input
                  onChange={(e) => this.handleChange(i, undefined, e)}
                  name="video_url"
                  type="file"
                  className="form-control pb-4"
                />
              </div>
              <br />
              {video_datas.subvideo_data.map((subvideo_datas, idx) => (
                <div className="container bg-success py-2" key={idx}>
                  <div className="main">
                    <div className="row">
                      <div className="form-group col-sm-6">
                        <label>Title:</label>
                        <input
                          type="text"
                          onChange={(e) => this.handleChange(i, idx, e)}
                          value={subvideo_datas.subvideo_title}
                          name="subvideo_title"
                          className="form-control"
                          placeholder="title"
                        />
                      </div>
                      <div className="form-group col-sm-6">
                        <label>Description:</label>
                        <input
                          type="text"
                          onChange={(e) => this.handleChange(i, idx, e)}
                          value={subvideo_datas.subdescription}
                          name="subdescription"
                          className="form-control"
                          placeholder="title"
                        />
                      </div>
                    </div>
                    <div className="form-group">
                      <label>Thambnail image:</label>
                      <input
                        name="subvideo_image"
                        onChange={(e) => this.handleChange(i, idx, e)}
                        type="file"
                        className="form-control"
                      />
                    </div>
                    <div className="form-group">
                      <label>Upload Video:</label>
                      <input
                        name="subvideo_url"
                        onChange={(e) => this.handleChange(i, idx, e)}
                        type="file"
                        className="form-control pb-4"
                      />
                    </div>
                    <br />
                    <Button
                      variant="danger"
                      onClick={() => this.removeTClick(i, idx)}
                    >
                      <FaTrashAlt style={{ marginRight: "5px" }} />
                      Remove
                    </Button>
                  </div>
                </div>
              ))}
              <div className="button-section" style={{ textAlign: "center" }}>
                <Button
                  variant="link"
                  className="addMoreBtn"
                  onClick={() => this.addTClick(i)}
                >
                  +Add More
                </Button>
              </div>
              {i ? (
                <Button
                  variant="danger"
                  onClick={() => this.removeFormFields(i)}
                >
                  <FaTrashAlt style={{ marginRight: "5px" }} />
                  Remove
                </Button>
              ) : null}
            </div>
          ))}
          <div className="button-section" style={{ textAlign: "center" }}>
            <Button className="addMoreBtn" onClick={this.addFTClick}>
              +Add chapter
            </Button>
            {/* 提交按钮 */}
            <Button type="submit" variant="primary" style={{marginLeft: '10px'}}>
              提交获取JSON
            </Button>
          </div>
        </form>
      </Container>
    );
  }
}

export default Forms;

效果说明

点击提交按钮后,this.state.video_data就是你需要的JSON数组格式数据,直接打印或者发起接口请求即可。文件类型字段会存储对应的File对象,如果需要转成base64或者FormData格式提交,可自行扩展处理逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:24:01