不少时候,一些开发者在呈现列表的时候喜欢用index(索引)做为其关键字(key)npm
咱们都知道在React中,在渲染相邻同级元素(siblings)时须要给每个item指定相应的key做为惟一标识符,如一组li,为了方便在页面发生变化是,即render树进行diff时,没有发生变化的element就不作更改。安全
可是在使用key的时候,不少人都习惯用列表的索引做为关键字,看起来很优雅,简洁。可未曾想到他暗藏着潜在的漏洞。bash
list.map((item,index)=>{
return <li key={index}>{...item}</li>
})
复制代码
由于key是用来惟一标识一个元素的。当你向列表中添加一条数据或者移除某条数据时。若是该键与以前的相同,React会认为DOM元素表示的组件和之前是同样的。然而咱们想要的并不是如此。ui
举一个小栗子,使用 ==index== 做为keythis
class Home extends React.Component {
constructor() {
super();
this.state = {
list: [{name:'zs',id:1},
{name:'ls',id:2},
{name:'ww',id:3}]
};
}
addAheadItem() {
this.setState({
list: [{name:'zq',id:4}, ...this.state.list]
});
}
addBehindItem(){
this.setState({
list: [...this.state.list,{name:'zq',id:4}]
});
}
render() {
return (
<div>
<button onClick={() => {this.addAheadItem();}}>
添加到头部
</button>
<button onClick={() => {this.addBehindItem();}}>
添加到尾部
</button>
//使用index做为索引
<div>
{this.state.list.map((item, index) => {
return (
<li key={index}>
{item.name}
<input type="text" />
</li>
);
})}
</div>
//使用id做为索引
<div>
{this.state.list.map((item, index) => {
return (
<li key={item.id}>
{item.name}
<input type="text" />
</li>
);
})}
</div>
</div>
);
}
}
render(<Home/>,document.getElementById('root'))
复制代码
事实证实,当使用index做为索引的时候,添加到头部的数据的input输入框会显示之前的内容。url
列表里面的每一项都应该有一个永久而且惟一的属性,理想状况下应该在建立列表的时候分配下去. 固然我指的是id. 咱们能够像下面这样使用它:spa
{todos.map((todo) =>
<Todo {...todo}
key={todo.id} />
)}
复制代码
另外的实现方式是把编号递增添加到抽象方法中,使用一个全局的index来确保任何两个列表项的id不一样code
todoCounter = 1;
function createNewTodo(text) {
return {
completed: false,
id: todoCounter++,
text
}
}
复制代码
一个产品化的解决方案是它应该更加健壮,可以用来建立分散的列表项. 所以我强烈推荐一个npm包shortid, 它能够快速的生成一系列‘短的 无序的 对url友好的 惟一的’ id,下面是示例代码:索引
var shortid = require('shortid');
function createNewTodo(text) {
return {
completed: false,
id: shortid.generate(),
text
}
}
复制代码
或许你会很疑惑,我是否老是要生成ID,不少人认为使用index做为key也不错。的确,每次都生成Id会显得冗余。那么总结一下,在如下几种状况下能够安全的使用index做为索引。element