我不确定这是否是一个反应问题,但我在这个问题上苦苦挣扎。我试图创建一个简单的例子来发布我的项目:
https://codepen.io/as3script/pen/VMbNdz?editors=1111
示例中有四个按钮。
要重现此问题,请按前三个按钮中的每个按钮以创建文本输入并输入值。例如,在第一个中输入100,在第二个中输入200,在第三个中输入300。现在按第四个按钮删除第一个输入。
它应该保留第二个和第三个值各自的值200和300,但它在第二个中显示100,在第三个中显示200个。
此代码与CodePen上的代码相同,它只是不允许在没有此情况下发布链接。
class ButtonComponent extends React.Component {
constructor(props) {
super(props);
this.state = {filtersArr:[]}
this.addButtons = this.addButtons.bind(this);
this.removeButtons = this.removeButtons.bind(this);
this.getInput = this.getInput.bind(this);
this.onChangeHandler = this.onChangeHandler.bind(this);
}
addButtons(e){
let tempArr = this.state.filtersArr;
tempArr.push({comp:this.getInput(e.target.id), id:e.target.id});
this.setState({filtersArr:tempArr});
}
removeButtons(e){
console.log(e.target.id);
let newArr = this.state.filtersArr.filter((filter)=>{
return (filter.id !=='FirstButton')
})
this.setState({filtersArr:newArr});
}
onChangeHandler(e){
console.log(e.target.value);
}
getInput(id){
return (
<div>
<h6>{id}</h6>
<input
id="min"
type="text"
placeholder="min"
onChange={this.onChangeHandler}/>
</div>
)
}
render() {
let styles = {
display:'inline-block'
}
return (
<div>
<p>Add three buttons and enter the number in each input, and remove amt.</p>
<button id="FirstButton" onClick={this.addButtons}>FirstButton</button>
<button id="SecondButton" onClick={this.addButtons}>SecondButton</button>
<button id="ThirdButton" onClick={this.addButtons}>ThirdButton</button>
<button id="FirstButton" onClick={this.removeButtons}>Remove firstButton</button>
<ul>
{this.state.filtersArr.map((filter, index)=>{
return <li style={styles} key={index}>{filter.comp}</li>
})
}
</ul>
</div>
);
}
}
ReactDOM.render(
<ButtonComponent/>,
document.getElementById('root')
);
答案 0 :(得分:2)
问题是您使用数组索引作为key
,因此React将重用前两个li
元素并删除最后一个元素。将key={index}
更改为key={filter.id}
,它可以正常运行。
有关评论的更新&amp; downvote:假设该字段名为id
,我假设实际代码中的过滤器具有唯一性。 CodePen似乎更像是一个精简版本来显示问题。但是如果你确实希望让每个按钮创建多个文本字段,那么你确实需要添加额外的东西以区分密钥(例如计数器)。这不会影响问题中所述的问题。
再次查看代码,我注意到getInput
将是提取到单独(无状态)组件的理想候选者,例如FilterInput
。这比使反应模型更好地适合于将子渲染保持在组件状态。
答案 1 :(得分:1)
代码在div中生成3个文本框。通过输入数字(100,200,300)来更新这些文本框。单击RemoveFirstButton时,将更新存储这些组件的状态并调用render。
渲染函数执行当前状态和先前状态的diff并删除包含数字300的最后一个div。这是因为,对于渲染函数,数组的第一个元素从FirstButton更改为SecondButton,第二个元素从SecondButton变为ThirdButton,第三个元素不再存在。
为了使其按预期工作,您需要将元素的键从数组的索引更改为元素的id,以便render方法可以区分元素。
答案 2 :(得分:0)
修改强>: 如果您的初始示例建议可以添加多个相同的元素,请避免使用您的ID作为其他答案建议的密钥,因为密钥需要是唯一的,这样他们可以(并且将会)重复!
您的问题在于您错误地使用了键属性。 React期望您的组件具有常量键,因此它可以决定何时以及需要更新哪些组件。
如果要修改数组,则对象的键会发生变化,并且具有键的元素会被更改为&#39; 1&#39;在删除之后,以及之前有关键的组件&#39; 2&#39;成为一个有关键的&#39; 1&#39;等等。
React documentation建议不要使用索引作为关键字:
&#34;如果商品可以重新排序&#34;
为了避免这种情况,你应该使用某种独特的密钥生成,并将每个组件密钥存储在它自己的对象中,例如:
在构造函数中:
this.nextKey = 0
添加新组件时:
tempArr.push({comp: comp, id: e.target.id, key: this.nextKey++});
在渲染功能中:
return <li style={styles} key={filter.key}>{filter.comp}</li>
我修改了你的例子以包含这些行,你可以在这里找到它: https://codepen.io/Isti115/pen/MEmMZP?editors=1111
另外,还有其他一些提示:
创建一个具有从具有相同名称的变量赋值的键的对象时,可以将其缩短以便:
{comp: comp, id: e.target.id}
成为这个:
{comp, id: e.target.id}
。
如果您需要更强大的功能,可以使用单独的唯一密钥生成器,如下所示:
Create GUID / UUID in JavaScript?
或者这个:
https://gist.github.com/gordonbrander/2230317
ps。:您正在使用的switch语句现在完全没用。你试图用它做什么?