事情的起因是这样的,有个同事写出了类似一下这样的写法:
长话短说:只要flag不是高频变化的,那这么写大部分情况是没问题的,不会触发后面节点的重新生成问题。
我当时看到后灵光一闪,想到之前看到React的旧文档中有一段说是新增节点最好不要往头部新增,可能会有性能问题:
于是想当然的认为上面的写法触犯了这个天条,便信誓旦旦的说这不行,会有性能问题,应该往后面加,这样React不会重建后面的所有元素。
但同事是个比较较真的人,他回去怎么调试怎么打印都没发现Comp2有重建的迹象,无论是在dom上勾选了各种断点:
还是直接保存变化前后的dom引用做对比:
结果都是完全相等!
遭到质疑的我便开始源码调试的旅程。
1. 定位源码位置
感谢DeepSeek \(^o^)/~
2. 调试关键位置
按我的理解,如果产生了性能问题,那么就会是从 [Comp2] -> [Comp1, Comp2] 的过程,那么首先它们没有key,React会用下标作为对比依据,那么一定会有一次 Comp2 和 Comp1 的比较,他们的elementType必不相等,会触发重新创建的流程,代码位置:
下断点,过到newChildren是[Comp1, Comp2]的时候,进入updateElement方法,于是看到了这一幕:
current是null,也就是说Comp1是在和null比,那Comp2呢,不就是原来的Comp2吗,那就不可能触发重新构建树的问题吧,这里回过神来,flag && <Comp1 />在flag是false的时候,并不是什么都没留在那里,不还有个false在那里吗,只是没渲染而已~
结论就是:flag为false的时候渲染的时候是 [false, Comp2], 更新后渲染的是[Comp1, Comp2],Comp2的位置一直是1,不存在重新创建树的问题。
后记:回头想想好像是个很容易理解的事情,但被刚学习时的先入为主的观念影响了,在深入使用后竟然也没发觉一些浅显的误区,还是不够较真啊。
收获还是有的,对React渲染子节点列表、key的作用、协调的算法流程有了更加深刻的理解~