React复杂表单编辑键值对

时间:2017-06-13 04:13:10

标签: javascript reactjs

我正在构建一个表单来编辑一个键/值对象,见图:

Key Value Pair Editor

这是我从后端获得的对象,我存储在容器组件中。

items: [{
    name: "Product Name",
    sku: "00001",
    attributes: {
        width: "value",
        height: "value",
        length: "value",
        color: "value"
    }
},
{
    name: "Product Name 2",
    sku: "00002",
    attributes: {
        description: "Hello World",
        weight: "250",
        quantity: "500",
        hello: "World"
    }
}]

然后我通过道具将数据传递给子组件。这是表单的代码:

class EditForm extends Component {
    render() {
        let editForm = this.props.items && this.props.items.map((item, idx) => {
            return(
                <tr key={item.sku}>
                    <td className="edit-table">
                        <input 
                            value={item.name}
                            name={item.name}
                            onChange={(e)=> this.props.onChange(e, idx)}
                        />
                    </td>
                    <td className="edit-table">
                        <ul className="item-attributes">
                            {Object.keys(item.attributes).map((key) => {
                                return (<li key={key}>
                                                    <label>{key}</label>
                                                    <input 
                                                        value={item.attributes[key]} 
                                                        onChange={(e) => this.props.onChange(e, idx) }
                                                    />
                                                </li>)
                            })}
                        </ul>
                    </td>
                </tr>
            )
        })

        return(
            <table className="editcontainer-table">
                <thead>
                    <tr>
                        <th>SKU</th>
                        <th>Attributes</th>
                    </tr>
                </thead>
                <tbody>
                    {editForm}
                </tbody>
            </table>
        );
    }
}

现在,这就是我被困住的地方,我正在试图找出onChange函数如何为我编辑状态中的对象并发送回服务器进行更新。

2 个答案:

答案 0 :(得分:1)

  1. 为项目名称输入name="name"属性
  2. 根据属性提供属性输入名称:name={key}
  3. 您现在可以识别onChange中正在编辑的内容 - 根据要更改的索引和输入名称进行适当的状态更改。

    e.g。 (使用import update from 'immutability-helper'onChange可能如下所示:

      onChange = (e, index) => {
        let {name, value} = e.target
        let updateSpec
        if (name === 'name') {
          updateSpec = {
            [index]: {
              name: {$set: value}
            }
          }
        }
        else {
          updateSpec = {
            [index]: {
              attributes: {
                [name]: {$set: value}
              }
            }
          }
        }
        this.setState({items: update(this.state.items, updateSpec)})
      }
    

    这是一个展示此解决方案的示例应用:

答案 1 :(得分:1)

我会将您的Container中的onChange函数更改为以下内容:

&#13;
&#13;
onChange = (e, sku, field) => {
  const updatedItems = this.state.items.map(e => { 
    if (e.sku !== sku) return e;
    if (field === 'name') {
      e.name = e.target.value;
    } else {
      // has to be attributes
      e.attributes[field] = e.target.value;
    }
    return e;
  });
  this.setState({
    items: updatedItems,
  })
}
&#13;
&#13;
&#13;

添加了sku参数以标识items数组中的项目以及要更改的字段。由于sku不会改变,我们可以将其用作项目标识符。这样,您可以更改产品名称及其各自的属性。有关完整的工作代码,请参阅下面的代码示例。

&#13;
&#13;
class Container extends React.Component {
  constructor() {
    super();
    this.state = {
      items: [{
        name: "Product Name",
        sku: "00001",
        attributes: {
          width: "value",
          height: "value",
          length: "value",
          color: "value"
        }
      },
      {
        name: "Product Name 2",
        sku: "00002",
        attributes: {
          description: "Hello World",
          weight: "250",
          quantity: "500",
          hello: "World"
        }
      }],
    }
  }
  
  onChange = (e, sku, field) => {
    console.log(e.target.value);
    const updatedItems = this.state.items.map(item => { 
      if (item.sku !== sku) return item;
      if (field === 'name') {
        item.name = e.target.value;
      } else {
        // has to be attributes
        item.attributes[field] = e.target.value;
      }
      return item;
    });
    this.setState({
      items: updatedItems,
    })
  }
  
  render() {
    // log new state here
    console.log(this.state.items);
    return <EditForm onChange={this.onChange} items={this.state.items} />
  }
  
}

class EditForm extends React.Component {
  render() {
    let editForm = this.props.items && this.props.items.map((item, idx) => {
      return(
        <tr key={item.sku}>
          <td className="edit-table">
            <input 
                value={item.name}
                name={item.name}
                onChange={(e)=> this.props.onChange(e, item.sku, 'name')}
            />
          </td>
          <td className="edit-table">
            <ul className="item-attributes">
              {Object.keys(item.attributes).map((key) => {
                  return (<li key={key}>
                                      <label>{key}</label>
                                      <input 
                                          value={item.attributes[key]} 
                                          onChange={(e) => this.props.onChange(e, item.sku, key) }
                                      />
                                  </li>)
              })}
            </ul>
          </td>
        </tr>
      )
    })

    return(
      <table className="editcontainer-table">
        <thead>
          <tr>
            <th>SKU</th>
            <th>Attributes</th>
          </tr>
        </thead>
        <tbody>
           {editForm}
        </tbody>
      </table>
    );
  }
}

ReactDOM.render(<Container />, document.getElementById('app'));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
&#13;
&#13;
&#13;