多个子组件的更新说明key的重要性
- 第一种无key情况:
更新前:
<div>
<Test text={'one'}/>
<Test text={'two'}/>
</div>
更新后:
<div>
<Test text={'one'}/>
<Test text={'two'}/>
<Test text={'three'}/>
</div>
第一种情况,diff算法如何更新
react通过对比虚拟Dom,通过虚拟算法先更新
<Test text={'one'}/>
<Test text={'two'}/>
但是因为实际内容并未改变,我们可以通过shouldComponent来阻止其更新,
然后<Test text={'three'}/>之前没有,所以添加一个实例,完成更新
- 第二种无key情况
更新前:
<div>
<Test text={'one'}/>
<Test text={'two'}/>
</div>
更新后:
<div>
<Test text={'three'}/> // 新加的位置放在了第一位
<Test text={'one'}/>
<Test text={'two'}/>
</div>
此时如何更新;
此时react的diff算法不是简单的在首尾添加一个<Test text={'three'}/>就完成更新
因为react新旧Dom对比是按照位置来的比较的,也就是说:
<Test text={'one'}/> ----- <Test text={'three'}/>
<Test text={'two'}/> ----- <Test text={'one'}/>
null ----- <Test text={'two'}/>
我们发现:由于添加的组件位置在首尾,现在不仅要新增一个组件
原来的两个组件即使一样,由于位置不同,相当于内容(props)都改变了,就得执行reconcile进行内容更新
由于react的diff算法认为props都改变了,所有必须更新
也无法通过shouldComponent来阻止更新来优化
(第一种方法位置相互对应,props没变可以通过shouldComponent来阻止更新优化)
- 第三种有key更新
更新前:
<div>
<Test key={'a'} text={'one'}/>
<Test key={'b'} text={'two'}/>
</div>
更新后:
<div>
<Test key={'c'} text={'three'}/> // 新添加的
<Test key={'a'} text={'one'}/>
<Test text={'b'}/ text={'two'}>
</div>
此时diff算法更新方式
<Test key={'a'} text={'one'}/> -比较- <Test key={'a'} text={'one'}/>
<Test text={'b'}/ text={'two'}> -比较- <Test text={'b'}/ text={'two'}>
null -比较- <Test key={'c'} text={'three'}/>
所以即使新添加的组件位置在首尾,但是因为有key,
diff算法会根据key去让相应的组件对比,然后确定怎么更新
所有这样以来,‘one' 'two'组件就用原来的props来启动更新,
通过shouldComponent来阻止更新,进行优化
- 注意key的使用
一个组件中的key必须唯一,而且必须稳定,如果key变来变去,会使react作出错误判断,甚至错误的渲染
key和ref都是react保留的特殊prop,无法通过this.props.key读取
- 为什么不要使用遍历的index作为key
##单个react组件性能优化小窍门
- 利用react-redux的shouldComponent
diff算法可以减少dom的操作,优化性能
但是比较新旧Dom,依然是个复杂的计算过程,特别是庞大项目dom多
所以如果能够渲染前判断渲染结果不会有变化,那么阻止virtual Dom计算比较,速度更快
- react为什么要采取这种策略
增加复用策略
在react中,每一个组件,在组件序列中唯一的标识符就是他的位置
但组件发生变化的时候,没有key就按照顺序来对比其是否发生变化,然后决定是否更新
即使A B 变成了C B A也不会复用A B,因为顺序变了,会强迫更新C B然后添加A
为什么react采取这种不聪明的做法了?
很简单,如果想要复用,就得计算出子组件序列的不同之处,他的复杂度为O(N2)
而采取傻瓜式的算法复杂度为O(N)
而为了避免浪费所以建议使用key来区分