专栏首页2014前端笔记一篇文章告诉你React里为什么不能用index作为key

一篇文章告诉你React里为什么不能用index作为key

之前在写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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • React 16.3 新的生命周期和context api

    一段时间以前,我们写了一篇文章有关我们即将升级我们遗留的生命周期方法,包含着我们慢慢的迁移的策略。在React 16.3.0这个版本中,为了慢慢迁移,我们增加了...

    2014v
  • Tree-shaking VS dead code elimination 【翻译】

    这里是原文链接Tree-shaking versus dead code elimination

    2014v
  • 年轻时,我不写单元测试

    当我们被提出这些bug的时候,我们是二脸懵逼的,因为这不符合一个程序员的预期!!! 那么我们如何能够避免以上的问题,从而将经历投入到更多的开发(写bug)中去...

    2014v
  • wepy repeat标签循环渲染bug解决

    子组件的show控制这个子组件的是否展示的状态,当我们绑定了点击事件之后,点击其中一个子组件。全部几个用repeat渲染出来的子组件都会同时消失或者显示,而不是...

    flytam
  • Silverlight RIA Service开发实战总结(一)

    Silverlight RIA Service开发实战总结(一) 如何更新(新增实体)domainService和metadata class 第一次使用向...

    阿新
  • Qt 5.11.1 静态编译

    离线安装包:http://download.qt.io/archive/qt/5.11/5.11.1/

    我与梦想有个约会
  • React的小案例:&amp;&amp;运算符、元素变量、三目运算符与React的条件渲染都在这里了

    用户1272076
  • 关于“分类”的应用 原

    三、SQL中区分类别的过滤条件:比如取分类2,那么就是 2=2 <![CDATA[ & ]]>type

    wuweixiang
  • Nebula3绘制2D纹理

    逍遥剑客
  • Git分支合并选择

       用Git进行多人协作开发时,必然会合并代码,解决冲突。然而合并代码也是需要点技巧的,如果对一些关键命令没有理解去使用的话,git的版本演进路线就会变得很乱...

    牧云云

扫码关注云+社区

领取腾讯云代金券