【问题标题】:React - differentiating between dynamically generated inputs on a formReact - 区分表单上动态生成的输入
【发布时间】:2016-06-14 02:38:44
【问题描述】:

我有一个表格中的数据输入表单,它根据有多少列生成输入。但是,我正在努力分离输入,以便当我更改其中一个值时,所有输入都会更改。有什么方法可以区分它们,以便我可以在每个输入中输入不同的值。我正在使用带有通量的 React。

这是我目前正在使用的代码:

import React from 'react';
import AppStore from '../../stores/AppStore';

export default class RowForm extends React.Component {
    state = {input: ''};
    onChange = (e) => {
        this.setState({input: e.target.value});
        console.log(input);
    };

    editStop = () => {
        this.props.editStop();
    };

    handleSubmit = (e) => {
        e.preventDefault();

        let access_token = AppStore.getToken();
        let id = AppStore.getTable().id;

        this.props.handleSubmit(access_token, id);

    };

    render() {

        let {input} = this.state;
        let dataEntries = AppStore.getTable().columns; //this gets the amount of columns so I can map through them and generate the correct amount of inputs.

        return (
            <tr>
                {dataEntries.map((element, index) => {
                    return (
                        <td key={index}><input type="text" className="form-control" id={element.id} placeholder="enter data" value={this.state.input} onChange={this.onChange} /></td>
                    );
                })}
                <td>
                    <button className="btn btn-default" onClick={this.editStop}><i className="fa fa-ban"></i>Cancel</button>
                    <button className="btn btn-success" onClick={this.handleSubmit}><i className="fa fa-check"></i>Save</button>
                </td>
            </tr>
        );
    }
} 

任何帮助将不胜感激,尤其是示例!

感谢您的宝贵时间

【问题讨论】:

    标签: reactjs reactjs-flux


    【解决方案1】:

    您可以在onChange 处理程序中创建一个匿名函数:

    <input key={index} onChange={event => this.onChange(event, index)}/>
    

    但是,更大的问题是您没有将AppStore.getTable().columns 映射到任何地方的状态,因此您根本无法修改组件状态。此外,您在 React 中使用 ES6 类不正确。

    class RowForm extends React.Component {
      constructor (props) {
        super(props);
    
        this.state = {
          inputs: {0: null, 1: null, 2: null}
        };
      }
    
      onChange (event, index) {
        this.setState({inputs[index]: event.target.value});
      }
    }
    

    如果您需要映射AppStore.getTable().columns,您应该将该数据作为道具传递下来。将 props 映射到 state 是一种反模式。

    class App extends React.Component {
      constructor () { // initialize stuff... }
    
      componenDidMount () {
        this.setState({columns: AppStore.getTable().columns});
      }
    
      onChange (event, index) {
        this.setState({columns[index]: event.target.value});
      }
    
      render () {
        <RowForm columns={this.state.columns} handleChange={this.onChange}/>
      }
    }
    
    class RowForm extends React.Component {
      constructor (props) {
        super(props);
      }
    
      render () {
        <div>
          {this.props.columns.map(index => {
            return <input onChange={event => this.props.handleChange(event, index)}/>
          })}
        </div>
      }
    }
    

    但是,当调用 onChange 时,这不会更新 AppStore。为此,您需要以某种方式跟踪全局状态。我建议查看Redux


    更新答案以尝试在当前条件下修复代码:

    class RowForm extends React.Component {
      // Set `dataEntries` to an empty array. This will prevent errors
      // from appearing in between `render` and `componentDidMount`.
      // e.g.: `this.state.dataEntries.map` is undefined or not an Array.
      // You may want to make this a little bit more fail safe though.
      state = {dataEntries: []};
    
      onChange = (event, element) => {
          // This assumes `element` is a string based on the column name.
          this.setState({dataEntries[element]: event.target.value});
      }
    
      componentDidMount () {
          // Set state with columns from the table.
          // Whenever this component mounts it will reset to the state
          // from `AppStore` unless you set up event listeners like in
          // Flux or migrate to Redux
    
          // This also assumes that `getTable().columns` returns an array
          // of column names. I don't know what your data structure looks
          // like so it's hard for me to help here. You need to turn the
          // array into an object to store values in the keys.
    
          let dataEntries = AppStore.getTable().columns.reduce((obj, name) => {
              obj[name] = null;
              return obj;
          }, {});
          this.setState({dataEntries});
      }
    
      render () {
            let {dataEntries} = this.state;
    
            // It is not really recommended to use indexes here because
            // of the way React diffing works. If `element` is a string
            // you can use that as the key/index instead. Also, it needs
            // to be unique within the array.
            // Turn dataEntries back into an array so map will work properly.   
            return (
                <tr>
                    {Object.keys(dataEntries).map((element) => {
                        return (
                            <td key={element}><input type="text" className="form-control" id={element} placeholder="enter data" value={dataEntries[element]} onChange={event => this.onChange(event, element)} /></td>
                        );
                    })}
                    <td>
                        <button className="btn btn-default" onClick={this.editStop}><i className="fa fa-ban"></i>Cancel</button>
                        <button className="btn btn-success" onClick={this.handleSubmit}><i className="fa fa-check"></i>Save</button>
                    </td>
                </tr>
            );
        }
    }
    

    【讨论】:

    • 我正在使用一些 es7 初始化程序,这就是为什么我没有使用 es6 的构造函数。不幸的是,我现在必须不断地构建,但我试图做到这一点,以便我可以开始使用 redux。您的回答确实有很大帮助,但是在 onChange 事件中,如何将索引映射到列?当我运行构建任务时出现错误?!
    • 我更新了答案以尝试提供帮助。您需要将 AppStore 映射到组件本地状态。我已经向您展示了如何使用上面的 cmets 执行此操作。不过,我强烈建议从当地迁移。祝你好运!
    • 感谢您的帮助,迈克!我几乎让它工作了,但是当我尝试在输入中输入数据时,它从多个输入变为单个输入,你知道为什么会发生这种情况吗?
    • 没关系自己修!再次感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2013-10-04
    • 2021-09-06
    • 2012-01-02
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    • 2018-05-07
    • 1970-01-01
    相关资源
    最近更新 更多