airi 项目中的 VueUseuseArrayFind:让Array.find具备响应式的实践指南
【免费下载链接】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-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi
useArrayFind是 VueUse 提供的响应式Array.find,它把原生数组查找逻辑包装成 Vue 计算属性:当数组或查找条件发生变化时,返回值会自动更新。本文以 airi 仓库内置的 useArrayFind 参考文档 为骨架,结合仓库中 Vue 3 应用(stage-web、stage-tamagotchi 等)对 VueUse 的实际使用方式,讲解它的用法、类型签名、响应式原理,以及它与useArrayFindIndex、useArrayFindLast等数组家族函数的搭配场景,帮助你写出更简洁、可维护的 Vue 业务代码。
useArrayFind 是什么
在 Vue 组件中,我们经常需要根据状态从列表中"找出第一个符合条件的元素",例如根据用户选择找到对应的配置项、根据 ID 找到当前播放的音频等。传统的做法是在computed里手写:
import { computed } from 'vue' const list = ref([1, -1, 2]) const positive = computed(() => list.value.find(val => val > 0))useArrayFind将这个模式固化成一个官方 composable,语义即 "ReactiveArray.find",调用方式与原生find几乎一致,却自动获得了响应式追踪能力。在 airi 仓库中,@vueuse/core通过 pnpm catalog 统一管理版本(见 pnpm-workspace.yaml,当前为^14.4.0),SKILL.md 中的 Array 分类表将其Invocation标记为AUTO,意味着在 Vue/Nuxt 开发中遇到"从数组中查找元素"的需求时,应当优先选用它而不是手写computed。
基本用法
对 ref 数组执行查找
useArrayFind接受两个参数:第一个是源数组,第二个是测试函数(predicate),返回值是一个ComputedRef,读取时需要访问.value:
import { useArrayFind } from '@vueuse/core' import { ref } from 'vue' const list = [ref(1), ref(-1), ref(2)] const positive = useArrayFind(list, val => val > 0) // positive.value: 1注意上面示例中list的每个元素本身也是 ref,useArrayFind的类型签名明确支持这种MaybeRefOrGetter<T>[]的嵌套形式——数组的元素可以是原始值、ref 或 getter,函数内部会统一解包后再执行测试。
与 reactive 数组联动
useArrayFind的真正价值在于与响应式数据结构联动:当数组内容发生变化(如push、splice)时,计算结果会自动重算,无需手动触发:
import { useArrayFind } from '@vueuse/core' import { reactive } from 'vue' const list = reactive([-1, -2]) const positive = useArrayFind(list, val => val > 0) // positive.value: undefined(当前没有正数) list.push(1) // positive.value: 1(数组变化后自动更新)这段代码展示了一个关键特性:当找不到任何满足条件的元素时,返回值是undefined(与原生Array.find一致);一旦数组被push进符合条件的元素,positive.value立即更新为1。
类型签名与参数语义
原文档给出了完整的 TypeScript 声明,理解它能避免误用:
export type UseArrayFindReturn<T = any> = ComputedRef<T | undefined> export declare function useArrayFind<T>( list: MaybeRefOrGetter<MaybeRefOrGetter<T>[]>, fn: (element: T, index: number, array: MaybeRefOrGetter<T>[]) => boolean, ): UseArrayFindReturn<T>逐项解读:
list: MaybeRefOrGetter<MaybeRefOrGetter<T>[]>:第一参数可以是一个 ref、getter 或普通数组;数组元素同样可以是 ref 或 getter。这解释了为何[ref(1), ref(-1), ref(2)]这种"ref 元素数组"可以直接传入。fn: (element, index, array) => boolean:测试函数签名与原生Array.find一致,接收当前元素、下标和整个数组(此处元素已被解包为T),返回布尔值决定是否命中。- 返回值
ComputedRef<T | undefined>:结果是一个计算属性,读取用.value;未命中时为undefined,文档注释明确:"the first element in the array that satisfies the provided testing function. Otherwise, undefined is returned." @__NO_SIDE_EFFECTS__:标注该函数无副作用,便于打包器做 tree-shaking 与死代码消除。
由于返回ComputedRef,你可以在模板中直接使用,也可以在另一个computed中依赖它形成链式推导,例如"先找到当前选中的配置,再读取它的某个字段"。
与原生 find 的对比及适用边界
| 对比维度 | 原生Array.find | useArrayFind |
|---|---|---|
| 数据源 | 普通数组,一次性查询 | ref / reactive / getter 数组,自动响应式 |
| 结果形态 | 普通值 | ComputedRef(.value访问) |
| 结果更新 | 需手动重新调用 | 数据或条件变化时自动重算 |
| 未命中结果 | undefined | undefined |
| 典型场景 | 一次性处理静态数据 | 列表来自状态、随用户操作增删改的动态数据 |
需要说明的边界:useArrayFind依赖 Vue 的响应式追踪,因此源数组必须是响应式的(ref、reactive 包裹,或数组元素为 ref/getter),或者依赖查找条件的变化来触发重算;对完全静态的数据,直接用原生find即可,不必引入额外开销。
在 airi 仓库中的应用场景
airi 仓库的多个 Vue 应用均通过 catalog 依赖@vueuse/core,包括 stage-web、stage-tamagotchi、stage-pocket、ui-server-auth 等。在这些应用的源码中存在大量"从响应式列表里按条件取首元素"的写法,它们都是useArrayFind的典型应用场景。例如:
- CharacterItem.vue 中多次出现
props.character.i18n.find(...)、props.character.capabilities.find(c => c.type === 'llm')这类查找; - mcp.vue 中通过
servers.value.find(...)、servers.value.findIndex(...)按名称或 rowId 定位 MCP 服务器配置项。
按照 SKILL.md 的指导原则——"先检查 VueUse 函数能否满足需求,优先使用 composable 而非手写代码"——当这些查找的数据源本身就是响应式状态时,改用useArrayFind可以直接把"手写 computed + find"缩减为一行声明式调用,让依赖关系由框架自动维护。
数组家族:从 find 到整个响应式数组工具链
useArrayFind属于 VueUse 的 Array 分类,SKILL.md 中列出了一整套"响应式数组方法",彼此可以自由组合:
useArrayFindIndex:响应式Array.findIndex,返回第一个命中的下标而非元素;useArrayFindLast:响应式Array.findLast,从数组末尾向前查找;useArrayFilter:响应式Array.filter,返回所有命中的元素数组;useArrayEvery、useArraySome:响应式every/some,用于断言;useArrayIncludes、useArrayUnique、useSorted等:覆盖成员判断、去重、排序等常见需求。
这些函数共用同一套入参约定(MaybeRefOrGetter<MaybeRefOrGetter<T>[]>)与ComputedRef返回约定,因此学会useArrayFind后可以零成本迁移到其他数组操作。选择建议:只需第一个命中元素用useArrayFind;需要下标用useArrayFindIndex;需要全部命中用useArrayFilter;需要从尾部找用useArrayFindLast。
小结
useArrayFind以极小的心智成本把原生find变成响应式声明:list支持 ref/reactive/getter 三种形态,测试函数签名与原生一致,返回值统一为ComputedRef<T | undefined>。在 airi 这类大量依赖 Vue 3 响应式状态的项目中,它适合用来替代"手写 computed + find"的样板代码,让"根据状态查找首个元素"的逻辑由框架自动保持同步。想深入了解完整类型与用法,可随时查阅仓库内置的 useArrayFind.md,并对照 SKILL.md 中的 Array 分类表选择合适的数组 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-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考