React中的key值
在React中,jsx的循环是很常见的,但加入在循环中不加入唯一的key值,则会有以下的警告:Warning: Each child in a list should have a unique "key" prop。那不加key和加key,对于React又有什么区别呢?而且,我们经常也被告知不推荐用与数据无直接关联的index(序号)来做key值。
不带key值
我们先map生成一些没有key的值,再通过事件修改其值。最后以DOMNodeRemoved事件是否触发来判断diff结果。
class IndexPage extends React.Component {
constructor(props) {
super(props)
this.state = {
arr: ['a', 'b', 'c', 'd']
}
}
componentDidMount() {
// 第一个元素
document.getElementById('a0').addEventListener('DOMNodeRemoved', function() {
alert()
})
// 第四个元素
document.getElementById('a3').addEventListener('DOMNodeRemoved', function() {
alert()
})
}
change = () => {
const a = this.state.arr
// 新增一个数据
a.push('e')
// 修改老的数据
a[3] = 'D'
this.setState({
arr: a
})
}
render() {
return (
<div>
{
// 不带key的循环
this.state.arr.map((item, ind) => {
return <span id={ `a${ind}` }>{ item }</span>
})
}
<div>
<button onClick={ this.change }>change</button>
</div>
</div>
)
}
}
页面上显示由 abcd 变成了 abcDe ,但是DOM移除事件并没有触发,diff起效果了。也就是说尽管没有key值,但是React仍对这些数据做了diff,将需要更新的节点的内容替换。
带key值
略微修改以上代码,增加key值,每次以数组的index为key值,并在按钮事件触发之后给index加了前置量temp。
class IndexPage extends React.Component {
constructor(props) {
super(props)
this.state = {
arr: ['a', 'b', 'c', 'd'],
temp: 0
}
}
componentDidMount() {
// 第一个元素,此元素在第二次时会更换id值
document.getElementById('a0').addEventListener('DOMNodeRemoved', function() {
alert('a0')
})
// 第一个元素,此元素在第二次时不会更换id值
document.getElementById('a3').addEventListener('DOMNodeRemoved', function() {
alert('a3')
})
}
change = () => {
this.setState({
temp: 2
})
}
render() {
return (
<div>
{
this.state.arr.map((item, ind) => {
return <span id={ `a${ind}` } key={ ind + this.state.temp }>{ item }</span>
})
}
<div>
<button onClick={ this.change }>change</button>
</div>
</div>
)
}
}
按钮点击后,只弹出了a0。可是在实际过程中,数组中的值并没有改变,却销毁了key值改变了DOM。这也是不推荐使用index做key值的一大原因,而是建议与数据有较大关联性的值。
key值的作用
是不是渐渐的理解key的作用了呢?简单的概括如下图:
文字概括如下:
- 当存在key值,若key值改变,则直接销毁DOM,重新创建,若key没有改变,则检查属性是否需要更新。
- 当不存在key值,直接diff处理。