在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. 列表不會執行重排或篩選操做
相關文章
相關標籤/搜索