文章首發於github部落格
之前在寫react的時候,當我們做map迴圈的時候,當我們沒有一個唯一id來標識每一項item的時候,我們可能會選擇使用index
data.map((item, index) => {
return <li key={index}>{item}</li>
})
複製程式碼
但是其實當你使用index來作為唯一key的時候,其實是由一個大坑的,什麼坑呢?必須坑了你才知道,來看下面的這種情況:
class App extends React.Component{
constructor(props) {
super(props)
this.state = {
list: [{id: 1,val: 'aa'}, {id: 2, val: 'bb'}, {id: 3, val: 'cc'}]
}
}
click() {
this.state.list.reverse()
this.setState({})
}
splice() {
this.state.list.splice(1,1)
this.setState({})
}
render() {
return (
<ul>
<div onClick={this.splice.bind(this)}>delete</div>
<div onClick={this.click.bind(this)}>reverse</div>
{
this.state.list.map(function(item, index) {
return (
<Li key={index} val={item.val}></Li>
)
}.bind(this))
}
</ul>
)
}
}
class Li extends React.Component{
constructor(props) {
super(props)
}
componentDidMount() {
console.log('===mount===')
}
componentWillUpdate(nextProps, nextState) {
console.log('===update====')
}
render() {
return (
<li>
{this.props.val}
<input type="text"></input>
</li>
)
}
}
複製程式碼
頁面渲染好了之後,3個input輸入框依次輸入1,2,3: 當我們用index作為key的時候,點選reverse會發現,input輸入框還是1,2,3順序顯示,但是這並不符合我們的預期,控制檯中此時列印的也是update; 當我們用物件中的id作為key的時候,點選reverse,此時神奇的事情發生了,input輸入框變成了3,2,1,符合我們的預期,控制檯此時列印的也是update;
為什麼會這樣呢?
當我們傳入index作為key時,此時的key為0,1,2, 當我們點選reverse重新排序後,index傳進去的key還是0,1,2,此時react比較key=0時,發現只需要更新子節點的值就可以,於是只把item替換成了cc,而input則相反, 當我們傳入id作為index的時候,,點選reverse後,此時的key變成了3,2,1,根據react的diff演算法,react還是能分辨出只需要移動子節點即可完成更新,因此input也隨之變化。
那說了這麼多,其實對於index作為key我們是不推薦的,除非你能夠保證他們不會發生變化。
參考文獻 index as a key is an anti-pattern, 有問題可以在部落格下方留言,感謝star