airi 项目中的 useArrayUnique 实战指南:VueUse 响应式数组去重 Composable 的用法与原理
airi 项目中的 useArrayUnique 实战指南VueUse 响应式数组去重 Composable 的用法与原理【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi本篇技术指南聚焦 VueUse 的useArrayUnique—— 一个响应式数组去重Composable。在 airi 这样的多端 Vue 3 项目stage-web、stage-pocket、stage-tamagotchi、component-calling 等应用均通过 pnpm catalog 统一引入vueuse/core中它用于把元素去重这类纯逻辑从组件中抽离成声明式的响应式计算。读完本文你将掌握useArrayUnique的三种核心用法多 ref 数组、reactive 数组、自定义比较函数、类型签名细节、与 Vue 原生方案的对比以及在本仓库中的实际落点与适用边界。一、什么是 useArrayUniqueuseArrayUnique是 VueUse 提供的一个响应式唯一数组Composable它接收一个数组或其响应式变体返回一个ComputedRef其值永远是对源数组去重后的结果并且会随源数组的变化自动重新计算。你不需要手动维护去重逻辑也不需要在每次数据变化后手动调用uniq()。在 airi 中vueuse/core是工作区级别的共享依赖版本由 pnpm-workspace.yaml 中的 catalog 统一锁定为^14.4.0vueuse/shared同版本各应用只需在package.json中声明vueuse/core: catalog:即可使用例如 apps/stage-web/package.json、packages/stage-ui/package.json。useArrayUnique正是该核心包中 Array 分类下的一员。二、基础用法一多个 ref 组成的数组useArrayUnique的第一个特色能力是可以传入一个由多个 ref 组成的数组并对每个 ref 解包后的值进行去重。import { useArrayUnique } from vueuse/core const item1 ref(0) const item2 ref(1) const item3 ref(1) const item4 ref(2) const item5 ref(3) const list [item1, item2, item3, item4, item5] const result useArrayUnique(list) // result.value: [0, 1, 2, 3] item5.value 1 // result.value: [0, 1, 2]要点解读list是一个普通数组但元素是 refuseArrayUnique会自动解包unref每个元素因此去重比较的是解包后的值0, 1, 1, 2, 3结果为[0, 1, 2, 3]。当item5.value从3改为1后源数组变为[0, 1, 1, 2, 1]去重结果自动更新为[0, 1, 2]——这印证了它是响应式的而非一次性计算。这种refs 数组形态非常契合 Vue 组件中由多个独立状态拼装的场景例如由多个下拉选择、标签开关聚合出的候选值集合。三、基础用法二reactive 数组第二种常见用法是传入一个reactive数组此时useArrayUnique会深度追踪数组内容的变化push、splice、索引赋值等都会触发重算import { useArrayUnique } from vueuse/core const list reactive([1, 2, 2, 3]) const result useArrayUnique(list) // result.value: [1, 2, 3] list.push(1) // result.value: [1, 2, 3]要点解读初始list [1, 2, 2, 3]去重后为[1, 2, 3]保留首次出现的顺序重复项被剔除。list.push(1)后虽然数组长度变为 5但由于1已存在结果仍是[1, 2, 3]——去重逻辑与源数组的增删改完全解耦UI 上绑定的result不会产生多余渲染。四、进阶用法三自定义比较函数对象去重当数组元素是对象或需要自定义相等语义时可以传入第二个参数compareFn。此时唯一性由该函数决定不再依赖严格相等import { useArrayUnique } from vueuse/core const list reactive([ { id: 1, name: foo }, { id: 2, name: bar }, { id: 1, name: baz }, ]) const result useArrayUnique(list, (a, b) a.id b.id) // result.value: [{ id: 1, name: foo }, { id: 2, name: bar }] list.push({ id: 1, name: qux }) // result.value: [{ id: 1, name: foo }, { id: 2, name: bar }]要点解读compareFn以(a, b) boolean的形式定义两个元素是否视为相同。本例按id判断因此{ id: 1, name: baz }被判定为与{ id: 1, name: foo }重复而被剔除。保留策略结果保留每个等价类中的第一个元素foo与bar被保留后续重复者丢弃。动态追加{ id: 1, name: qux }后结果不变因为id为 1 的等价类已存在。该模式非常适合去重从服务端拉取的、带唯一主键的对象列表或在 airi 的舞台/UI 状态中按id聚合标签、成员、配置项等对象集合。五、类型声明与参数语义从本仓库 references/useArrayUnique.md 中记录的官方类型声明可以看到完整的签名export type UseArrayUniqueReturnT any ComputedRefT[] export declare function useArrayUniqueT( list: MaybeRefOrGetterMaybeRefOrGetterT[], compareFn?: (a: T, b: T, array: T[]) boolean, ): UseArrayUniqueReturnT参数与返回值逐项说明成员类型说明listMaybeRefOrGetterMaybeRefOrGetterT[]源数组。既可以是普通数组也可以是ref/reactive数组甚至可以是由 getter 返回的数组数组元素同样支持ref会自动解包compareFn(a: T, b: T, array: T[]) boolean可选自定义相等判定不传时默认使用严格相等返回值UseArrayUniqueReturnTComputedRefT[]去重后的数组以只读ComputedRef形式暴露通过.value读取几个容易忽略的细节惰性计算返回的是ComputedRef采用 Vue 的惰性求值机制——只有被读取时才会计算且结果会被缓存直到源数组的依赖发生变化。这意味着在模板或计算属性中引用它是零额外开销的。compareFn的第三个参数array与Array.prototype的sort/findIndex回调类似比较函数还会收到当前参与比较的完整数组作为第三个参数可满足更复杂的去重语义。泛型推断T由list元素类型自动推断当元素是对象时compareFn的a、b参数也会获得完整的对象类型提示。函数标注了__NO_SIDE_EFFECTS__表示调用useArrayUnique本身不产生副作用可安全用于组合式函数的顶层或条件分支配合unrefElement、computed等同类 VueUse 函数保持一致的可预测行为。六、与原生方案的对比为什么用 ComposableuseArrayUnique本质上是把以下三段手写逻辑收敛成一个声明式 API手写const seen new Set(); const uniq list.filter(...)式的去重循环用computed(() ...)包裹去重逻辑并维护依赖追踪处理数组元素本身是 ref / getter时的解包细节。对比来看纯函数方案[...new Set(arr)]只能去重原始值Set基于 SameValueZero无法处理对象自定义相等性也不具备响应性数据变化后需手动重新调用。手写 computed 方案能获得响应性但需要自己处理ref元素解包、对象比较函数、类型标注等边界代码易重复。useArrayUnique 方案一行调用即获得响应式 可定制比较 类型安全的完整能力且返回ComputedRef可直接用于模板或与其他 VueUse 数组工具如useSorted、useArrayMap、useArrayFilter见 SKILL.md 的 Array 分类组合形成声明式数据管道。七、在本仓库中的适用场景与边界airi 是一个以 Vue 3 为 UI 技术栈的跨端项目Web / Capacitor / Electronvueuse/core被工作区所有前端包依赖例如 apps/stage-tamagotchi/package.json、packages/stage-ui-live2d/package.json。从仓库实际使用模式看如 apps/stage-web/src/composables/audio-input.ts 使用useDevicesList、packages/stage-ui/src/stores/providers/provider.ts 使用computedAsync等VueUse 组合式函数被广泛用于状态与 UI 逻辑useArrayUnique适合在其中处理以下场景去重来自多个数据源的 ID / 名称集合多个 ref 组成的数组避免重复渲染或重复请求按业务主键去重对象列表自定义compareFn例如合并多路推送的角色、插件、消息条目作为声明式数据管道的一环与useSorted排序、useArrayFilter过滤串联将过滤 → 去重 → 排序写成纯声明式链。边界与注意点引用类型去重必须传compareFn默认对两个不同引用的对象永远判定为不同不会按内容去重。保留首个元素当多个元素被判为相等时只保留第一次出现的那个若需要保留最后一个应自行调整输入顺序或改用其他逻辑。去重顺序稳定结果顺序与源数组中首个出现的等价元素的顺序一致不会重排。返回的是只读ComputedRef不要尝试直接result.value.push(...)修改去重结果应修改源list来驱动结果更新。八、小结useArrayUnique是 VueUse Array 家族中小而美的一员三个用法覆盖了 refs 数组、reactive 数组、对象自定义相等性三种典型诉求返回ComputedRef保证了惰性求值与自动响应类型声明则提供了从list到compareFn的完整泛型推导。在 airi 这类以 pnpm workspace Vue 3 为基础、统一通过 catalog 引入vueuse/core^14.4.0的多端仓库中将它作为去重逻辑的默认实现可以显著减少样板代码并让数据流保持声明式、可组合、可测试。【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考