React Native中如何阻止相同ID的item重复添加到状态数组
问题根因
列表渲染时使用商品对象的id字段作为React子元素的唯一key,但现有商品添加逻辑未做重复ID校验,直接将页面返回的商品数组全量追加到状态中,当待添加数组包含已存在ID的商品时,就会触发重复key警告,进而引发子元素重复渲染、丢失等异常。
原实现同时存在两处可优化点:
- 手动遍历
itemArray逐个push到新数组的操作属于冗余逻辑,可直接通过数组展开语法实现 - 直接读取闭包缓存的
items值做拼接,短时间多次触发状态更新时可能拿到过期的状态值,导致更新丢失,推荐使用React官方推荐的函数式更新写法
修复实现
核心逻辑:状态更新前先收集已有商品的全部ID,过滤掉待添加数组中ID已存在的重复项,再执行状态更新。
基础版修复代码
const AddItemToBill = (navigation) => { navigation.navigate('AddItemToBill', { onReturn: (itemArray) => { // 使用函数式更新,保证拿到的prevItems是最新状态 setItems(prevItems => { // 用Set存储已有ID,查询存在性的时间复杂度为O(1),性能优于数组遍历查询 const existingIdSet = new Set(prevItems.map(item => item.id)); // 过滤掉重复ID的商品 const validNewItems = itemArray.filter(item => !existingIdSet.has(item.id)); return [...prevItems, ...validNewItems]; }) }, navigation }) };
增强版(兼容待添加数组自身包含重复ID的场景)
如果页面返回的itemArray本身可能存在重复ID的项,可以在过滤时同步把新加入的ID存入集合,避免待添加数组内部的重复项进入状态:
const AddItemToBill = (navigation) => { navigation.navigate('AddItemToBill', { onReturn: (itemArray) => { setItems(prevItems => { const existingIdSet = new Set(prevItems.map(item => item.id)); const validNewItems = []; itemArray.forEach(item => { if (!existingIdSet.has(item.id)) { validNewItems.push(item); // 新ID加入集合,拦截待添加数组内部的重复项 existingIdSet.add(item.id); } }); return [...prevItems, ...validNewItems]; }) }, navigation }) };
实现说明
- 采用Set做ID存在性校验:当商品列表长度较大时,
Set.has()的查询性能远高于数组的includes、indexOf方法,页面响应更流畅 - 函数式更新保证状态正确性:回调参数中的
prevItems永远指向最新的状态值,彻底避免闭包缓存旧状态导致的更新错误 - 去重逻辑在状态更新前执行,从根源上保证状态数组中所有商品的ID唯一,不会再触发重复key警告
内容的提问来源于stack exchange,提问作者newdevv2
相关产品推荐
相关产品推荐

