我正在构建一个表单来编辑一个键/值对象,见图:
这是我从后端获得的对象,我存储在容器组件中。
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函数如何为我编辑状态中的对象并发送回服务器进行更新。
答案 0 :(得分:1)
name="name"
属性name={key}
您现在可以识别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
函数更改为以下内容:
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;
添加了sku参数以标识items数组中的项目以及要更改的字段。由于sku不会改变,我们可以将其用作项目标识符。这样,您可以更改产品名称及其各自的属性。有关完整的工作代码,请参阅下面的代码示例。
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;