V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
v135ex
V2EX  ›  React

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

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

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

    https://zh-hans.reactjs.org/docs/reconciliation.html#recursing-on-children
    jinliming2
        5
    jinliming2  
       2022-04-24 03:17:40 +08:00   ❤️ 1
    循环不加 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
        6
    AyaseEri  
       2022-04-24 09:30:14 +08:00   ❤️ 1
    不加 key 是会有算法去比对差异决定是否复用的,加 key ,可以实现强制刷新某组件的效果。
    Foryou920
        7
    Foryou920  
       2022-04-24 10:43:18 +08:00   ❤️ 1
    组件复用需要满足几个条件,key 属于其中一个条件:props 不变
    实际上,在 JSX 转换的时候,是会给组件一个默认的值为 null 的 key 的
    当一个组件的 props 不变、context 不变且自身的 state 状态不变,那么这个组件就会进入 bailout 逻辑,也就是组件复用
    v135ex
        8
    v135ex  
    OP
       2022-04-24 10:48:28 +08:00
    @Foryou920 通透!感谢!
    v135ex
        9
    v135ex  
    OP
       2022-04-24 10:49:21 +08:00
    @jinliming2 非常感谢知识传授!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1281 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 17:50 · PVG 01:50 · LAX 10:50 · JFK 13:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.