在React中index做为key是反模式的

不少时候,一些开发者在呈现列表的时候喜欢用index(索引)做为其关键字(key)npm

咱们都知道在React中,在渲染相邻同级元素(siblings)时须要给每个item指定相应的key做为惟一标识符,如一组li,为了方便在页面发生变化是,即render树进行diff时,没有发生变化的element就不作更改。安全

可是在使用key的时候,不少人都习惯用列表的索引做为关键字,看起来很优雅,简洁。可未曾想到他暗藏着潜在的漏洞。bash

list.map((item,index)=>{
    return <li key={index}>{...item}</li>
})
复制代码
Note:它可能会破坏你的应用程序并显示错误的数据

由于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

Better

列表里面的每一项都应该有一个永久而且惟一的属性,理想状况下应该在建立列表的时候分配下去. 固然我指的是id. 咱们能够像下面这样使用它:spa

{todos.map((todo) => 
    <Todo {...todo}
        key={todo.id} />
)}
复制代码

另外的实现方式是把编号递增添加到抽象方法中,使用一个全局的index来确保任何两个列表项的id不一样code

todoCounter = 1;
function createNewTodo(text) {
    return {
        completed: false,
        id: todoCounter++,
        text
    }
}
复制代码
much Better

一个产品化的解决方案是它应该更加健壮,可以用来建立分散的列表项. 所以我强烈推荐一个npm包shortid, 它能够快速的生成一系列‘短的 无序的 对url友好的 惟一的’ id,下面是示例代码:索引

var shortid = require('shortid');

function createNewTodo(text) {
    return {
        completed: false,
        id: shortid.generate(),
        text
    }
}
复制代码

或许你会很疑惑,我是否老是要生成ID,不少人认为使用index做为key也不错。的确,每次都生成Id会显得冗余。那么总结一下,在如下几种状况下能够安全的使用index做为索引。element

  1. 列表不被计算和改变。
  2. 列表项没有ID属性
  3. 列表不会执行重排或筛选操做
相关文章
相关标签/搜索