繁体   English   中英

从同一个组件中收集数据,这些数据被多次渲染到一个数组中,以发送到服务器

[英]Collect Data from the same component which is being rendered multiple times into an array to be sent to the server

我有一个创建页面,我要求用户一次又一次地填写同一个表单,用户想要的次数不限,一旦用户认为他们完成了填写表单,他们就可以点击提交按钮和所有数据在表单中将被发送到服务器。

我尝试在父组件上创建一个方法,并从同一个表单组件收集数据并将其发送回父组件。 但是我无法区分哪个表单正在发送数据。 如果用户在第一个表单中添加数据后进行了一些更改,然后再添加 3 个表单并填写它们,然后在将多个表单数据发送到服务器之前返回并对第一个表单进行更改。

import React, { Component } from 'react'
import { connect } from 'react-redux'
import BeneficiaryFilter from 
'../../Commons/Filter/Beneficiary/BeneficiaryFilter'
import './style.scss'
import IndividualVendor from './IndividualVendor/InvidualVendor'
import Select from 'react-select'

// import actions to get data
import { fetchCompanyConfiguration } from 
'../../../../redux/vendor_payments/dashboard/actions/newPayTicket'

class Beneficiary extends Component {
  constructor (props) {
    super(props)
    this.state = {
      vendorTotalAmount: 0,
      vendorTotalCount: 1,
      dataToBeSent: []
    }
  }

  /**
   *
   * Check for click event on name change , increase number of 
   *   vendor by one, nut just once.
   */
  vendorAdd = () => {
    this.setState({
      vendorTotalCount: this.state.vendorTotalCount + 1
    })
  }

  /**
    * @param {amount}, change the state value for total for the 
individual ticket and then send the amount to component that shows 
the total amount.
   */
  onVendorAmountChange = amount => {
    this.setState({
      vendorTotalAmount: amount
    })
  }

  componentDidMount () {
    this.props.dispatch(fetchCompanyConfiguration())
  }

  addVendorDetails = data => {
    let dataToBeSent = {...this.state.dataToBeSent}
    dataToBeSent[`Vendor${Date.now()}`] = data
    this.setState({
      dataToBeSent
    })
  }

  render () {
    const { newPayTicket } = this.props
    const { vendorTotalCount, vendorTotalAmount } = this.state
    let listOfVendors = [];
    for (let i = 1; i <= vendorTotalCount; i++) {
      listOfVendors.push(
        <IndividualVendor
          key={i}
          vendorAdd={this.vendorAdd}
          onVendorAmountChange={this.onVendorAmountChange}
          newPayTicket={newPayTicket}
          addVendorDetails={this.addVendorDetails}
          count={vendorTotalCount}
        />
      )
    }
    return (  
      <div className='beneficiary-container'>
        <BeneficiaryFilter
          vendorTotalCount={this.state.vendorTotalCount}
          vendorTotalAmount={this.state.vendorTotalAmount}
        />
        <div className='main-container'>
          <div className='add-beneficiary-container'>
            {listOfVendors}
          </div>
        </div>
      </div>
    )
  }
}

const mapStateToProps = state => {
  return {
    newPayTicket: state.newPayTicket.configurationData
  }
}
export default connect(mapStateToProps)(Beneficiary)

上面是我希望从每个组件添加数据的父组件。 单个组件有

State for the form, 
class Vendor extends Component {
  constructor (props) {
    super(props)
    this.state = {
      venodrName: '',
      vendorId: '',
      vendorAuthType: true,
      vendorAccountId: '',
      vendorAccountName: '',
      selectedBankAccountIfsc: '',
      selectedBankAccountNumber: '',
      unauthorisedBankAccountName: '',
      unAuthselectedBankAccountNumber: '',
      unAuthselectedBankAccountIfsc: '',
      vendorNarration: '',
      vendorCategoryId: '',
      vendorCostCenterId: '',
      vendorDepartmentId: '',
      vendorAmount: '',
      vendorTds: '',
      vendorGstDropdown: '',
      vendorGst: '',
      vendorDetails: {},
      errors: {}
    }
  }

IndividualVendor 组件只不过是一个具有可以填充的字段的表单,每次有人从当前表单切换到下一个表单时,我希望将字段中的所有数据添加到父组件的数组中,并且用户完成后,他们可以单击提交并发送父组件中 dataToBeSent[] 中收集的所有数据。

我不确定如何从多次渲染的相同组件中获取数据并将数据存储在父组件的对象中,我如何确保即使相同的表单也只存储一次表单数据一次又一次地被改变。

例如:如果我开始在 IndividualVendor 组件的第一个实例中添加信息,然后转到同一个 IndividualVendor 组件的下一个实例,我想确保父组件中的数组只有 2 个对象而不是新对象任何时候编辑/更改表单。 下面我添加了页面设计的模型,每一行项目都是IndividualVendor组件,容器是父组件。 希望所有这些都提供了足够的背景。

蒂亚!!

页面的模型设计

一种方法:

  1. 将状态提升到父组件,这意味着您的表单组件没有任何状态,并且只从 props 接收数据并渲染它。 父组件负责存储和更新数据。
  2. 给每个表单数据一个唯一的 id,以便于查找和更新它。

这是一个简单的例子( https://codesandbox.io/s/5v389j6vp4 ):

import React, { Component } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class Vendor extends Component {
  render() {
    const {
      vendorName,
      vendorNarration,
      vendorAmount,
      onChangeName,
      onChangeNarration,
      onChangeAmount
    } = this.props;

    return (
      <form onSubmit={e => e.preventDefault()}>
        Name : <input value={vendorName} onChange={onChangeName} /> <br />
        Narration :{" "}
        <input value={vendorNarration} onChange={onChangeNarration} /> <br />
        Amount : <input value={vendorAmount} onChange={onChangeAmount} /> <br />
        <hr />
      </form>
    );
  }
}

const DEFAULT_DATA = {
  vendorName: "",
  vendorNarration: "",
  vendorAmount: ""
};
class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      dataToBeSent: []
    };
  }

  addVendor() {
    this.setState(state => ({
      dataToBeSent: state.dataToBeSent.concat({
        id: Date.now(),
        ...DEFAULT_DATA
      })
    }));
  }

  handleOnChangeName(e, id) {
    const newData = this.state.dataToBeSent.map(data => {
      if (data.id !== id) {
        return data;
      }

      return {
        ...data,
        vendorName: e.target.value
      };
    });

    this.setState({ dataToBeSent: newData });
  }

  handleOnChangeNarration(e, id) {
    const newData = this.state.dataToBeSent.map(data => {
      if (data.id !== id) {
        return data;
      }

      return {
        ...data,
        vendorNarration: e.target.value
      };
    });

    this.setState({ dataToBeSent: newData });
  }

  handleOnChangeAmount(e, id) {
    const newData = this.state.dataToBeSent.map(data => {
      if (data.id !== id) {
        return data;
      }

      return {
        ...data,
        vendorAmount: e.target.value
      };
    });

    this.setState({ dataToBeSent: newData });
  }

  renderForms() {
    const { dataToBeSent } = this.state;

    return dataToBeSent.map(data => (
      <Vendor
        key={data.id}
        {...data}
        onChangeName={e => this.handleOnChangeName(e, data.id)}
        onChangeNarration={e => this.handleOnChangeNarration(e, data.id)}
        onChangeAmount={e => this.handleOnChangeAmount(e, data.id)}
      />
    ));
  }

  render() {
    return (
      <div className="App">
        <button onClick={this.addVendor.bind(this)}>Add Vendor</button>
        {this.renderForms()}
        <hr />
        <h4>Result</h4>
        <div>{JSON.stringify(this.state.dataToBeSent, null, 2)}</div>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

编辑

每次有人开始在任何字段中输入时,我如何处理添加卡片的另一个问题?

https://codesandbox.io/s/vvm4lj3nqy

  1. 为每个表单数据添加一个布尔值dirty: false
  2. 在每个输入更改设置dirty: true
  3. componentDidUpdate检查是否至少有一个带有dirty: false表单,如果没有则添加它。

像这样

  componentDidUpdate(prevProps, prevState) {
    if (prevState.dataToBeSent !== this.state.dataToBeSent) {
      const clean = this.state.dataToBeSent.find(data => !data.dirty);

      if (!clean) {
        // Add clean form
        this.addVendor();
      }
    }
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM