我在Angular中有类似的代码,效果很好。我试图将代码转换为React版本。效果很好,除非我尝试删除行。每次删除单击都会删除最后一行。我的期望是删除我单击“删除”按钮的行。我正在传递需要删除的索引项。我提供了以下示例,您也可以在这里尝试... https://jsfiddle.net/w6cy0bx1/11/
class MineCts extends React.Component{
constructor(props){
super(props);
this.state = {
items:[]
};
}
render(){
return(
<div>
<div><button onClick={(event)=>this.add(event)} >Add</button></div>
<div>
This is sample:
{this.state.items.map((record, index)=>{
return(
<table>
<tr key={index}>
<td> <input id="Name" value={record.Name} onChange={this.onDataChange}/> </td>
<td> <input id="Counter" value={record.Counter} onChange={this.onDataChange} /> </td>
<td><button onClick={(event)=>this.remove(event, record, index)} >Remove</button></td>
</tr>
</table>
)
})}
</div>
</div>
)
}
onDataChange(e)
{
console.log(e.target.id)
this.setState({[e.target.id]:e.target.value})
}
add(e){
let rows = this.state.items;
rows.push({});
this.setState({items:rows})
}
remove(e, record, index){
console.log(record)
console.log(index)
let rows = this.state.items;
rows.splice(index, 1);
this.setState({items:rows})
}
}
ReactDOM.render(<MineCts />, mountNode)
答案 0 :(得分:1)
仔细检查后,发现问题的原因是
<tr key={record.index}>
实际上并没有设置,您没有给孩子使用的唯一密钥,因此React不知道这些孩子中的哪个已被修改,因此当您删除其中一个孩子时,它会有些混乱。 / p>
您需要为每个记录提供唯一的密钥。
我更新了您的代码,并使用new Date().getTime()
作为获取唯一密钥的快速方法。
我在https://jsfiddle.net/xk4e1z2s/2/
处有一个工作示例在添加每个记录的唯一键时,您会看到它们的值,并且您会注意到只有特定的行被删除了。
在删除一行后,输入字段为空的原因是,您需要保存记录的输入值。
答案 1 :(得分:1)
您可以在删除功能上直接执行setState。
我的意思是;
remove(index) {
this.setState({
items: this.state.items.filter((s, sindex) => index !== sindex),
});
}
答案 2 :(得分:0)
感谢大家的反馈。这非常有帮助。我了解到,如果要使用React行,则需要具有唯一的键。使用过滤器代替“拼接”也很有帮助。我必须添加更改事件。将一个组件组合成多个组件后,我发现它非常有用。我更新了解决方案,以便在删除单行后不会清除输入字段。我还意识到,与Angular React不同,它只执行一种方式绑定,并且每个数据更改都必须通过状态进行更新。这是完整的解决方案:https://jsfiddle.net/wfcev8zb/30/。特别感谢user2340824的持续反馈。 这是最终代码:
class MineCts extends React.Component{
constructor(props){
super(props);
this.state = {
items:[]
};
this.add = this.add.bind(this);
this.onDataChange = this.onDataChange.bind(this);
this.remove = this.remove.bind(this);
}
render(){
return(
<div>
<div><button onClick={this.add} >Add</button></div>
<div>
This is sample:
{this.state.items.map((record, index)=>{
return(
<DetailTable record ={record} callOnChangeFunc={this.onDataChange} callOnRemoveFunc={this.remove} />
);
})}
</div>
</div>
)
}
onDataChange(e, record)
{
e.preventDefault();
let rows = [...this.state.items];
record[e.target.id]=e.target.value;
rows[record.Id] = record;
this.setState({items:rows})
}
add(e){
let rows = [...this.state.items];
rows.push({Id: new Date().getTime(), Name:null, Counter:null});
this.setState({items:rows})
}
remove(e, record){
e.preventDefault();
let rows = [...this.state.items.filter(x=>x.Id!==record.Id)];
this.setState({items:rows})
}
}
class DetailTable extends React.Component{
constructor(props){
super();
this.callOnChange = this.callOnChange.bind(this);
this.callOnRemove = this.callOnRemove.bind(this);
}
callOnChange(e){
this.props.callOnChangeFunc(e, this.props.record);
}
callOnRemove(e){
this.props.callOnRemoveFunc(e, this.props.record);
}
render(){
return (
<div>
<table>
<tr key={this.props.record.Id} >
{this.props.record.Id}
<td>
<input id="Name" value={this.props.record.Name} onChange={this.callOnChange} /> </td>
<td>
<input id="Counter" value={this.props.record.Counter} onChange={this.callOnChange} /> </td>
<td><button onClick={this.callOnRemove} >Remove</button></td>
</tr>
</table>
</div>
);
}
}
ReactDOM.render(<MineCts />, document.querySelector("#app"))