不少時候,一些開發者在呈現列表的時候喜歡用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