相信初学者在学习React文档时都会注意到列表组件,并且官方会提醒列表组件需要key属性,虽然没有key属性React也能渲染出来,但会在控制台出现相应的warning。
为何需要key属性 由于React是基于Virtual DOM的diff算法来判断是否重新渲染组件,在列表组件数量比较多,但变化实际不多的情况(比如只插入一个),如果没有key属性辅助判断,需要重新加载其后所有的组件,这样对组件的渲染性能来说是一个灾难。
key值也就相当于列表组件的身份标识,React会根据该属性是否变化来判断组件是否更改,从而决定如何更新组件:
key相同 ,若组件属性有所变化,则react只更新组件对应的属性;没有变化则不更新。
key值不同 ,则react先销毁该组件(有状态组件的componentWillUnmount会执行),然后重新创建该组件(有状态组件的constructor和componentWillUnmount都会执行)1
我们来看这一段代码,代码定义了8秒后刷新列表内容,我们在8秒内在子组件输入组件的英文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class List extends Component { constructor (props) { super(props); this.state = { list: ['🍎', '🍌'] }; this.timerId = setTimeout(() => { this.setState({ list: ['🍓', '🍌', '🍎'] }); clearTimeout(this.timerId); }, 8000); } render () { return ( <ul className='text'> { this.state.list.map((key, index) => { return ( <ListItem key={index} value={key}/> ); }) } </ul> ); } } class ListItem extends Component { componentWillMount () { console.log(this.props.value, 'will mount'); } componentDidMount () { console.log(this.props.value, 'did mount'); } componentWillUpdate () { console.log(this.props.value, 'will update'); } componentDidUpdate () { console.log(this.props.value, 'did update'); } render () { return ( <li> 组件 {this.props.value} <input style={{marginLeft: '20px'}} /> </li> ); } }
使用index作为key属性,
看看在列表更新后,React会如何更新显示结果:
可以看出,按照索引重新加载的组件认为组件没变,只是属性发生改变,所以内部输入框的内容没有发生改变,但这一般来说并不是我们想要的,从打印出的log也能看出,列表组件的其实与内部内容已经无法对应了。
1 2 3 4 5 6 7 8 9 10 11 12 13 🍎 will mount 🍌 will mount 🍎 did mount 🍌 did mount 🍎 will update 🍌 will update 🍎 will mount 🍓 did update 🍌 did update 🍎 did mount
那么使用列表中的内容作为key属性呢
可以看出,列表组件的刷新与内部内容是对应的
1 2 3 4 5 6 7 8 9 10 11 12 13 🍎 will mount 🍌 will mount 🍎 did mount 🍌 did mount 🍓 will mount 🍌 will update 🍎 will update 🍓 did mount 🍌 did update 🍎 did update
用什么值作为key属性 在充分理解这个属性之前,一直习惯用数组的索引作为key,竟然也没有深入地去想过这个问题,直到被面试官问到,惭愧。
一般来说,如果纯粹是展示组件,且仅与父组件状态相关,其实使用索引与内容作为key属性问题并不大;
如果涉及到较多的状态更新或自身携带状态,应该使用能够稳定、唯一化、与内容严格对应的key属性。
[1] http://www.cnblogs.com/wonyun/p/6743988.html