关于 react diff 算法加 key 想请教大家

2022-04-24 00:01:51 +08:00
 v135ex
本人不才,最近在看源码学习,发现单节点和多节点 diff 中,都是会判断 key 与 tag 是否相同才决定是否复用。如果 key 不相同则会直接删除 old node 。我的问题是,官方只推荐了在列表循环渲染时使用 key ,那在其他组件我并没有使用 key ,那就意味着其他组件都不会被复用吗?
1914 次点击
所在节点    React
9 条回复
v135ex
2022-04-24 00:02:19 +08:00
看的有些浅显,还希望大家指教。
v135ex
2022-04-24 00:04:01 +08:00
还某一个问题,如果我不使用循环渲染,直接手写 10 个 li ,也不加 key ,好像 react 也不会给我警告,是不是也是侧面证实了我的猜想呢?
seki
2022-04-24 01:16:16 +08:00
不用 key 的情况下 react 会自动用比较小的代价来复用

循环里面用 key 是为了让 react 更容易找到循环中变更的部分
zhihuzeye
2022-04-24 02:06:08 +08:00
按照 Reconciliation 的设计,没有 key 的情况会按顺序遍历比对。
比如在尾端追加元素的场景里,原来的元素都是可以被复用的;但在头部塞入元素则会影响整个列表,类似的还有删除任一非尾部元素、调整列表顺序。

https://zh-hans.reactjs.org/docs/reconciliation.html#recursing-on-children
jinliming2
2022-04-24 03:17:40 +08:00
循环不加 key 可以理解为默认就是用 index 做 key 的。
之所以循环会报警告而你手写 10 个 li 不会报警告,是因为循环通常是对一个数组变量进行的,数组是会变动的,一旦数组发生中间插入 /删除,react 不能简单的判断出变更位置,只能全部遍历重新更新做 diff ,所以需要你提供 key 信息来辅助定位。而手写的话,你所有写出来的 Node 位置都一定是确定的,即便是你在中间有写条件语句来控制是否输出,在隐藏的时候也会保留一个空 Node ,可以利用这些信息来判断变更发生的位置。
比如:
<li>1</li>
{show && <li>2</li>} // 隐藏时是个 false
{show ? <li>3</li> : null} // 隐藏时是个 null
<li>4</li>
在 show 为 false 的时候,渲染结果是 [<li>1</li>, false, null, <li>4</li>],4 个成员,show 为 true 的时候是 [<li>1</li>, <li>2</li>, <li>3</li>, <li>4</li>],也是 4 个成员,因此 react 是完全知道你的更新位置在哪的。
AyaseEri
2022-04-24 09:30:14 +08:00
不加 key 是会有算法去比对差异决定是否复用的,加 key ,可以实现强制刷新某组件的效果。
Foryou920
2022-04-24 10:43:18 +08:00
组件复用需要满足几个条件,key 属于其中一个条件:props 不变
实际上,在 JSX 转换的时候,是会给组件一个默认的值为 null 的 key 的
当一个组件的 props 不变、context 不变且自身的 state 状态不变,那么这个组件就会进入 bailout 逻辑,也就是组件复用
v135ex
2022-04-24 10:48:28 +08:00
@Foryou920 通透!感谢!
v135ex
2022-04-24 10:49:21 +08:00
@jinliming2 非常感谢知识传授!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/848844

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX