您现在的位置是:亿华云 > IT科技类资讯
React 中的列表渲染为什么要加Key
亿华云2025-10-04 03:50:06【IT科技类资讯】2人已围观
简介大家好,我是前端西瓜哥,今天来学习 React 中的列表渲染要加 key 的原因。在 React 中我们经常需要渲染列表,比如展示好友列表。常用写法是用 Arrary.prototype.map 方法
大家好,表渲我是什加前端西瓜哥,今天来学习 React 中的表渲列表渲染要加 key 的原因。
在 React 中我们经常需要渲染列表,什加比如展示好友列表。表渲
常用写法是什加用 Arrary.prototype.map 方法,将数组形式的表渲数据映射为 JSX.Element 数组,并嵌入到组件要返回的什加 JSX.Element 中,如下:
function FriendList() {
const [items,表渲 setItems] = useState([前端西瓜哥, 小明, 张三]);
return (
{ items.map((item) => (
))}
);
}你需要给每个项提供 key 属性作为标识,以区分不同的什加项。如果你不加 key,表渲React 会警告你:
Warning: Each child in a list should have 什加a unique "key" prop.为什么需要 key?
在回答这个问题之前,我们先简单了解一下 React 的表渲 DOM Diff 算法原理。
React 会在状态发生变化时,什加对真实 DOM 树按需批量更新,表渲产生新的 UI。
为此底层做的工作是:将新旧两棵虚拟 DOM 树进行 diff 对比,计算出 patch 补丁,打到真实 DOM 树上。
为了高效,React 的 diff 算法做了限制:
只做同层级的节点对比,服务器托管不跨层级比较。如果元素的类型不同(如从 p 变成 div),那它们就是不相同的,会销毁整个旧子树,并调用其下组件的卸载钩子,然后再创建全新的树,相当消耗性能。如果类型相同,会进行打补丁操作(如更新 className 和标签下的文本内容)。但这样做会有一个问题,如果同级的多节点 只是位置发生了变化,但因为相同索引位置对不上,又发现不能复用,就要销毁一棵树并创建一棵新树,实在是太过于低效了。
于是 React 给开发者提供 key 来标记节点,来优化 React diff 算法,告知 React 某个节点其实没有被移除或不能被原地复用,只是换了位置而已,让 React 更新一下位置。
列表渲染不提供 key 会怎样?
不提供 key,React 就无法确定某个节点是亿华云计算否移动了。
React 就只会对比相同位置的两个节点,如果它们类型相同(比如都是 li 元素),就会对比 props 的不同,进行 props 的打补丁。
因为 列表渲染通常都是相同的类型,所以位置变动时,多半是会触发节点原地复用效果,倒是不用担心树的销毁重建发生。
原地复用在不提供 key 的时候有时候也是能正确渲染的。
除了一种情况,就是 这个节点有自己的内部状态,最经典的莫过于输入框。
function FriendList() {
const [items, setItems] = useState([前端西瓜哥, 小明, 张三]);
const swap = () => {
[items[0], items[1]] = [items[1], items[0]];
setItems([...items]);
};
return (
{ items.map((item) => (
))}
交换
);
}我们给第一和第二个输入框输入内容。
再点击 “交换” 按钮,交换数组第一和第二个元素位置。
然后我们看到 input 前面的文字正确交换了,站群服务器但是输入框里的内容却没有交换。
原因是 React 做了原地复用,而 input 没有传 props,不需要打 props 补丁,保持了原样。
这个问题怎么解决?加 key。让 React 知道你的节点需要移动,你得这样写:
items.map((item) => (
不使用 key 的另一个缺点是:因为原地复用会使传入的 props 发生变化,导致不能利用好 React.memo 的组件缓存能力。
列表渲染的 key 用数组索引会怎样?
效果和不使用 key 相同,依旧是新旧节点的相同索引位置对比,但是控制台不会打印警告。
应该用什么值作为 key?
对于节点,你需要用一个唯一的 id 赋值给 key,通常会是数组的 id,比如后端返回的好友列表的好友 id。
const [items, setItems] = useState([
{ id: 5, name: 前端西瓜哥 },
{ id: 9, name: 小明 },
{ id: 87, name: 张三 },
{ id: 91, name: 前端西瓜哥 }
]);
const list = items.map((item) => (
如果后端没有返回 id,你可以自己手动用一个 id 生成器补上一个 id,虽然不太优雅就是了。比如:
const items = [前端西瓜哥, 张三];
const genId = (() => {
let i = 0;
return () => {
return i++;
}
})();
const itemsWithId = items.map(item => ({ id: genId(), val: item }));
// [{ id: 0, val: 前端西瓜哥}, { id: 1, val: 张三}]对了,这个 key 只需要在同一个层级的节点唯一即可,不要求所有层级的 key 都是唯一的。
另外,如果你确保你的列表渲染后直到被销毁,不会有位置上的变化,可以使用数组索引为 key。
结尾
对于列表的渲染,我们有必要提供 key,来对节点进行区分,React 的 DOM Diff 算法会基于 key 进行节点位置的调整,确保一些涉及到内部状态的节点的渲染状态。
通常来说,key 值应该是唯一的,通常来自后端返回的数据。在你确认列表不会发生位置变更时,可以使用数组索引作为 key,以去掉恼人的警告提示。
有一个点需要说明的是,key 并不是列表渲染的专属,普通的节点也可以用 key。
很赞哦!(76)
相关文章
- 因为域名解析需要同步到DNS根服务器,而DNS根服务器会不定时刷,只有DNS根服务器刷新后域名才能正常访问,新增解析一般会在10分钟左右生效,最长不会超过24小时,修改解析时间会稍微延长。
- FPGA编程从零开始 使用Verilog
- 适配混合云,货拉拉的数据库中间件建设之路
- 短域名该如何获取?有什么方法?
- 打开https://www.aizhan.com/输入自己想要查询的域名然后按回车键,如果做过网站都会有数据显示出来
- 十分钟搭建实验分布式数据库环境
- 深入理解分布式系统中的缓存架构(上)
- 提升CPU算力,在Python中使用多进程模型
- 要如何了解反向解析和域名解析?新手该怎么去操作?
- MySQL数据库查询好慢,除了索引,还能因为什么?