无法在 DataTable React Js 中设置输入元素的初始值和 onchange

Not able to set initial values and onchange of input elelements in DataTable React Js

我有一个从父组件到子组件 (DataTable) 的数据集。我正在用传入的数据创建一个数据表。我能够创建数据表,但我面临 2 个问题:

  1. 我无法在 Datatable 的输入元素中写入内容
  2. 我无法根据传入的数据设置输入框的初始值

我的目标是我想为所有输入设置一些初始值(动态的,基于数据)并且用户应该能够编辑输入值。

我是 React 的新手,我无法理解这个问题

以下是我的代码:

import react, {Component} from 'react';
import $ from 'jquery';

export default class Datatable extends Component{

    constructor(props){
        super(props)

        this.state = {
            value:""
        }

        this.generateHeader = this.generateHeader.bind(this);
        this.generateTableData = this.generateTableData.bind(this);
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(event){
        console.log("change clicked");
        this.setState({value: event.target.value});
    }

    generateHeader(){
        const columnHeader = ["Deposit name", "Amount"]
        let res=[];
        for(var i =0; i < columnHeader.length; i++){
            res.push(<th key={columnHeader[i]}>{columnHeader[i]}</th>)
        }
        return res;
    }

    generateTableData(){
        let tableData = this.props.snapshotData.data.deposits;
        let invenstments = tableData.Investment;
        let liquid = tableData.Liquid;
        let savings = tableData.Savings;
        let arr = $.merge(this.createRow(invenstments), this.createRow(liquid))
        let res = $.merge(arr, this.createRow(savings));
        return res;
    }

    createRow(data){
        let res=[];
        for(var i=0; i < data.length; i++){
            res.push(
                <tr>
                    <td key={data[i].name}>{data[i].deposit_name}</td>
                    <td key={data[i].id}><input type="text" value={this.state.value} onChange={this.handlehange} /></td>
                </tr>
            )
        }
        return res;
    }

    render(){
        return(
            <div className="row">
                <div className="col-12">
                    <div className="card">
                        <div className="card-header">
                          <h3 className="card-title">DataTable with default features</h3>
                        </div>
                        <div className="card-body">
                            <table id="example1" className="table table-bordered table-striped">
                                <thead>
                                  <tr>
                                    {this.generateHeader()}
                                  </tr>
                                </thead>
                                <tbody>
                                  {this.generateTableData()}
                                </tbody>
                                <tfoot>
                                  <tr>
                                    {this.generateHeader()}
                                  </tr>
                                </tfoot>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

我想设置为input values的初始值是:data[i].amount in createRow(data) method.

输入json格式如下:

{
    "data": {
        "deposits": {
            "Investment": [
                {
                    "amount": 1000.0,
                    "deposit_name": "Test 12",
                    "id": 12
                },
                {
                    "amount": 1000.0,
                    "deposit_name": "Test 13",
                    "id": 13
                }          
            ],
            "Liquid": [
                {
                    "amount": 1000.0,
                    "deposit_name": "Test 3",
                    "id": 3
                }
            ],
            "Savings": [
                {
                    "amount": 1000.0,
                    "deposit_name": "Test 1",
                    "id": 1
                },
                {
                    "amount": 1000.0,
                    "deposit_name": "Test 2",
                    "id": 2
                }
            ]
        }
    },
    "message": "success",
    "status": true
}

根据您在代码中分享的详细信息,我假设 Datatable 组件的使用方式如下:

<Datatable
  snapshotData={{
    data: {
      deposits: {
        Investment: [{ amount: 0, deposit_name: "", id: "" }, ...],
        Liquid: [{ amount: 0, deposit_name: "", id: "" }, ...],
        Savings: [{ amount: 0, deposit_name: "", id: "" }, ...],
      },
    },
  }}
/>

从那里开始,在不过多更改代码的情况下,我们需要确保初始状态包含正确的数据

我们会将您的逻辑从 generateTableData 移至构建阶段

这将帮助我们启动具有正确数据结构的组件:

constructor(props) {
  super(props);
  let tableData = this.props.snapshotData.data.deposits;
  let invenstments = tableData.Investment;
  let liquid = tableData.Liquid;
  let savings = tableData.Savings;
  let merged = [].concat(invenstments).concat(liquid).concat(savings);
  let state = {
    items: {},
    ids: []
  };
  for (var i = 0; i < merged.length; i++) {
    state.items[merged[i].id] = merged[i];
    state.ids.push(merged[i].id);
  }

  this.state = state;

  this.generateHeader = this.generateHeader.bind(this);
  this.generateTableData = this.generateTableData.bind(this);
  this.handleChange = this.handleChange.bind(this);
}

根据上面的逻辑,我们将有一个 this.state 看起来像:

this.state = {
  items: {
    12: {
     "amount": ...,
     "deposit_name": ...,
     "id": ...,
    },
    13: {...}
  },
  ids: [12, 13, 3]
}

此结构帮助我们“查找和更新”this.state.items 中的值,并使用 this.state.ids

迭代这些对象

现在 handleChange,我们需要查找正确的对象并为反应生成新状态:

handleChange(event) {
  let nextState = Object.assign({}, this.state);
  nextState.items[event.target.id].amount = event.target.value;
  this.setState(nextState);
}

我们在这里使用 Object.assign 来创建一个新对象(作为最佳实践,您不应该直接改变 this.state

新的 generateTableData() 函数只是迭代 this.state.ids 并调用 createRow:

generateTableData() {
  let res = [];
  for (var i = 0; i < this.state.ids.length; i++) {
    let id = this.state.ids[i];
    let item = this.state.items[id];
    res.push(this.createRow(item));
  }
  return res;
}

如您所见,this.state 中的新结构使查找 items/ids

变得容易

现在,最后一个主要变化是 createRow,我们不再需要使用数组:

createRow(data) {
  return (
    <tr key={data.id}>
      <td>{data.deposit_name}</td>
      <td>
        <input
          id={data.id}
          type="text"
          value={data.amount}
          onChange={this.handleChange}
        />
      </td>
    </tr>
  );
}

这样,我们就有了一个完整的工作演示: https://codesandbox.io/s/Whosebug-answer-dynamic-input-datatable-2zygh

完整代码在这里:

import { Component } from 'react';

export class Datatable extends Component {
  constructor(props) {
    super(props);
    let tableData = this.props.snapshotData.data.deposits;
    let invenstments = tableData.Investment;
    let liquid = tableData.Liquid;
    let savings = tableData.Savings;
    let merged = [].concat(invenstments).concat(liquid).concat(savings);
    let state = {
      items: {},
      ids: [],
    };
    for (var i = 0; i < merged.length; i++) {
      state.items[merged[i].id] = merged[i];
      state.ids.push(merged[i].id);
    }

    this.state = state;

    this.generateHeader = this.generateHeader.bind(this);
    this.generateTableData = this.generateTableData.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    let nextState = Object.assign({}, this.state);
    nextState.items[event.target.id].amount = event.target.value;
    this.setState(nextState);
  }

  generateTableData() {
    let res = [];
    for (var i = 0; i < this.state.ids.length; i++) {
      let id = this.state.ids[i];
      let item = this.state.items[id];
      res.push(this.createRow(item));
    }
    return res;
  }

  generateHeader() {
    const columnHeader = ['Deposit name', 'Amount'];
    let res = [];
    for (var i = 0; i < columnHeader.length; i++) {
      res.push(<th key={columnHeader[i]}>{columnHeader[i]}</th>);
    }
    return res;
  }

  createRow(data) {
    return (
      <tr key={data.id}>
        <td>{data.deposit_name}</td>
        <td>
          <input
            id={data.id}
            type="text"
            value={data.amount}
            onChange={this.handleChange}
          />
        </td>
      </tr>
    );
  }

  render() {
    return (
      <div className="row">
        <div className="col-12">
          <div className="card">
            <div className="card-header">
              <h3 className="card-title">DataTable with default features</h3>
            </div>
            <div className="card-body">
              <table
                id="example1"
                className="table table-bordered table-striped"
              >
                <thead>
                  <tr>{this.generateHeader()}</tr>
                </thead>
                <tbody>{this.generateTableData()}</tbody>
                <tfoot>
                  <tr>{this.generateHeader()}</tr>
                </tfoot>
              </table>
            </div>
          </div>
        </div>
      </div>
    );
  }
}