React在循环渲染时,为什么要设置key?如何正确设置key?

前段时间有个人问,react中想要循环列表时,为什么要设置key?

如果是在开发中碰到警告, 一看可能就会想到:哦,原来是循环忘记加 key 了,大概原因知道,但是其实还真没仔细想过为什么要加 key。所以查了相关文档,自己简单做下总结。

image

一。为什么要用key?

react 官方文档是这样描述 key 的:

keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个子元素赋予一个缺点的标识。 

react 的 diff 算法是把 key 当成唯一 id 后对比组件的 value 来确定是否需要更新的,所以说如果没有 key, react 将不会知道如何更新组件。

1.虚拟 DOM 和 diff 算法

React 最为核心的就是 Virtual DOM Diff 算法。React 在内存中维护一颗虚拟 DOM 树,当数据发生变化时(state & props),会自动地更新虚拟 DOM ,获得一个新的虚拟 DOM 树,然后通过 Diff 算法,比较新旧虚拟 DOM 树,找出最小的有变化的部分,将这个变化的部分(patch)加入队列 ,最终批量的更新这些 Patch 到实际的 DOM 中。

 React diff 原理(大厂必问)

1.把树形结构按照层级分解,只比较同级元素;

2.给列表结构的每个单元添加唯一的 key 属性,方便比较;

3.React 只会匹配相同的 class 的 component (这里的 class 指的是组件的名字);

4.合并操作,调用 component 的 setState 方法的时候,React 将其标记为 dirty 到每一个事件循环结束。React 检查所有标记 dirty 的 component 重新绘制;

5.选择性子树渲染。

二。使用 index 做 key 存在什么问题?

假设我们在 state 中有一个列表 [a, b, c ],在遍历渲染时用索引作为 key,那么就是这样:

a ---> 0
b ---> 1
c ---> 2

这个时候我们执行一个操作,点击删除数组中的 a,此时我们的数组列表为 [ b, c ],在遍历渲染时仍然会使用索引作为 key,结果如下:

b ---> 0
c ---> 1

看出区别了吗?此时的 key 是唯一的标记每一个列表吗?显然不是。

如果不适用索引做 key,程序额能快速的对比出差异,使用索引也能对比出差异,但是必须对整个 虚拟 DOM  做对比,这样大大消耗了新旧虚拟 DOM 的对比的性能。

三。如何使用正确的 key?

1.纯展示

如果组件单纯的用来展示,不会发生其他变更,那么使用 index 或者其他任何不相同的值做 key 都是可以的,因为不会发生 diff,就不会用到 key。 

2.子组件可能发生改变 / 使用了非受控组件

受控组件: 

1.每当表单的状态发生变化时,都会被写入到组件的 state 中;

2.在受控组件中,组件渲染出的状态与它的 value 或 checked prop 相对应;

3.react 受控组件更新 state 的流程。

流程

(1)通过在初始 state 中设置表单的默认值

(2)每当表单的值发生变化时,调用 onChange 事件处理器;

(3)事件处理器通过合成对象 e 拿到改变后的状态,并更新应用的 state

(4)setState 触发视图的重新渲染,完成表单组件值的更新。

使用受控组件需要为每一个组件绑定一个 onChange 事件,并且顶一个事件处理器来同步表单值和组件的状态,某些情况可以使用一个事件处理器来处理多个表单域。

受控 onChange  对应的检测属性:

文本框 ---> event.target.value

多选框 ---> event.target.checked

文本域 ---> event.target.value

下拉框 ---> event.target.value

非受控组件:  

1.如果一个表单组件没有 value prop 就可以称为非受控组件

2.非受控组件时一种反模式,它的值不受组件自身的 state 或 props 控制

3. 通常需要为其添加ref prop 来访问渲染后的底层的 DOM 元素

4.可通过添加 defaultValue 指定 value 值。

二者的区别: 

受控组件的状态由开发者维护,非受控组件的状态由组件自身维护。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值