React调用Spotify API返回专辑对象数组的去重实现方案
React调用Spotify API获取专辑列表的对象数组去重方案
问题场景
在React项目中调用Spotify API拉取艺人专辑JSON数据时,返回结果存在大量同名重复专辑,需要对存入useState对象数组状态的专辑数据做去重处理。
原实现逻辑为:请求接口后循环遍历返回条目,逐条调用setAlbums()追加到状态中,原代码如下:
const artistInfoHandler = (id) => { setLoading(true); setAlbums([]); fetch(`https://api.spotify.com/v1/artists/${id}/albums`, { headers: { Accept: "application/json", Authorization: `Bearer ${data.access_token}`, "Content-Type": "application/json", }, }) .then((response) => response.json()) .then((response) => { console.log(response); for (let i = 0; i < response.items.length; i++) { setAlbums((old) => [ ...old, { albumTitle: response.items[i].name, albumImage: response.items[i].images[0].url, }, ]); } }) .catch((error) => console.log(error)); setLoading(false); };
代码运行后得到的专辑列表存在大量重复,示例数据如下:
0: {albumTitle: 'Certified Lover Boy', albumImage: 'xxxxxxxxxxxx'} 1: {albumTitle: 'Certified Lover Boy', albumImage: 'xxxxxxxxxxxxxxxxxx'} 2: {albumTitle: 'Dark Lane Demo Tapes', albumImage: 'xxxxxxxxxxxxxxxxxx'} 3: {albumTitle: 'Dark Lane Demo Tapes', albumImage: 'xxxxxxxxxxxx'} // ...省略更多重复条目 19: {albumTitle: 'Nothing Was The Same', albumImage: 'xxxxxxxxxxxxxxxxxx'}
原始值类型数组使用的[...new Set(albums)]去重方案对对象数组无效。
问题原因
Set结构的去重逻辑基于SameValueZero相等判定,对于引用类型的对象,仅当两个对象引用地址完全一致时才会判定为相等。哪怕两个对象的属性、属性值完全相同,只要是不同的对象实例,Set也会判定为两个不同元素,因此无法直接用于对象数组去重。- 原代码存在两处逻辑缺陷:一是循环逐条调用
setAlbums会触发多次不必要的组件重渲染;二是setLoading(false)写在fetch请求外层,会在接口还未返回结果时就提前关闭加载状态,不符合交互逻辑。 - Spotify接口返回重复专辑的本质是同一张专辑会返回不同发行地区、不同版本的条目,需要业务侧自行根据唯一标识过滤。
实现方案
使用Map结构做去重缓存,选定专辑的唯一标识作为key判定重复,数据处理完成后一次性更新状态,同时修复原代码的加载态逻辑问题:
- 优先选择Spotify返回的专辑
id作为去重key(全局唯一,精准度最高),如果业务上需要按专辑名合并不同版本条目,也可以使用albumTitle作为去重key。 - 遍历接口返回的专辑条目,已存在于Map中的条目直接跳过,不存在则存入Map,最终将Map的value转为数组即为去重后的列表。
- 将loading状态的关闭逻辑放到
finally回调中,确保请求无论成功失败都能正确重置加载态。
修正后的完整代码如下:
const artistInfoHandler = (id) => { setLoading(true); setAlbums([]); fetch(`https://api.spotify.com/v1/artists/${id}/albums`, { headers: { Accept: "application/json", Authorization: `Bearer ${data.access_token}`, "Content-Type": "application/json", }, }) .then((response) => response.json()) .then((response) => { const albumMap = new Map(); response.items.forEach(item => { // 用专辑id做去重key精准度更高,换成item.name即可按专辑名去重 const uniqueKey = item.id; if (!albumMap.has(uniqueKey)) { albumMap.set(uniqueKey, { albumTitle: item.name, // 增加可选链兼容无封面的专辑数据,避免脚本报错 albumImage: item.images[0]?.url || '' }) } }) // 一次性更新去重后的列表,避免多次重渲染 setAlbums(Array.from(albumMap.values())) }) .catch((error) => console.log(error)) .finally(() => { setLoading(false); }); };
补充:如果不想保留第一条出现的专辑、需要自定义保留规则(比如优先保留高清封面的版本),可以在遍历到重复key时对比两个条目的属性,替换为符合要求的条目即可。
内容的提问来源于stack exchange,提问作者user11464857
相关产品推荐
相关产品推荐

