
airi 项目实战VueUse watchArray 深度解析——带增删差异回调的数组监视【免费下载链接】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在 airi 这个基于 Vue 3 的多端Web / macOS / Windows / Android / iOSAI 伴侣 monorepo 中响应式数组的状态监听是聊天会话、设备列表、权限配置等场景的常见需求。本文以仓库内置的 VueUse 参考文档 .agents/skills/vueuse-functions/references/watchArray.md 为主体完整讲解watchArray的语义、回调参数与类型声明并结合 airi 仓库的依赖配置与技能引导文件说明该 API 在本项目中的定位与适用边界读完后可在 airi 的任意 Vue 应用中正确选用它来实现只关心新增/移除项的精细监听。一、watchArray 解决什么问题Vue 原生的watch在监视数组时回调只能拿到newValue与oldValue两个完整快照。当数组很长或只发生了局部变化时业务代码往往还需要自己手动做两次 diff 才能知道到底谁被加了、谁被删了。watchArray来自vueuse/core它在watch的基础上把 diff 工作做在了框架层Watch for an array with additions and removals.Similar towatch, but provides the added and removed elements to the callback function. Pass{ deep: true }if the list is updated in place withpush,splice, etc.即与普通watch类似但会把新增元素与移除元素直接作为参数传给回调函数如果列表是通过push、splice等原地修改的需要传{ deep: true }才能被观测到。二、官方示例四参数回调的标准用法参考文档给出的完整示例如下可直接复制运行import { watchArray } from vueuse/core const list ref([1, 2, 3]) watchArray(list, (newList, oldList, added, removed) { console.log(newList) // [1, 2, 3, 4] console.log(oldList) // [1, 2, 3] console.log(added) // [4] console.log(removed) // [] }) onMounted(() { list.value [...list.value, 4] })示例演示了最典型的整体替换引用场景list.value [...list.value, 4]产生新数组引用后watch的依赖追踪自动触发added得到[4]removed为空数组。回调的五个参数语义如下参数类型含义value示例中newListT[]变更后的完整数组oldValue示例中oldListT[]immediate: true时可能为undefined变更前的完整数组added示例中addedT[]本次变化中新增的元素removed示例中removedT[]本次变化中被移除的元素onCleanup(cleanupFn: () void) void清理函数注册器与 Vuewatch语义一致用于在下次触发前清理定时器、事件等副作用注意文档示例中onMounted里才修改list是因为组件挂载前ref变化只会累积到挂载后批量触发这与 Vue 的 watcher 调度机制一致不影响watchArray本身的 diff 逻辑。原地修改时必须传 deep文档特别强调的一句实操要点是若通过push、splice、直接下标赋值等方式原地修改数组引用不变必须传{ deep: true }const list ref([1, 2, 3]) // 原地 push引用不变必须 deep 才能触发 watchArray(list, (_newList, _oldList, added, removed) { console.log(added) // [4] console.log(removed) // [] }, { deep: true }) list.value.push(4)这是因为 Vue 的浅层 watcher 只在数组引用变化时触发deep: true让依赖追踪深入到元素级别watchArray内部的 diff 才能拿到正确的新旧快照。而像示例中[...list.value, 4]这种新数组替换写法天然产生新引用不需要deep。三、类型声明逐行解读参考文档同时给出了 TypeScript 声明这是准确使用泛型与选项的依据export declare type WatchArrayCallbackV any, OV any ( value: V, oldValue: OV, added: V, removed: OV, onCleanup: (cleanupFn: () void) void, ) any /** * Watch for an array with additions and removals. * * see https://vueuse.org/watchArray */ export declare function watchArray T, Immediate extends Readonlyboolean false, ( source: WatchSourceT[] | T[], cb: WatchArrayCallbackT[], Immediate extends true ? T[] | undefined : T[], options?: WatchOptionsImmediate, ): WatchHandle可以提炼出四个关键设计点source的三种形态WatchSourceT[] | T[]意味着既能传入RefT[]/ComputedRefT[]/ getter 函数也能直接传一个响应式数组reactive 展开后的数组使用灵活度与原生watch保持一致。Immediate条件泛型Immediate extends Readonlyboolean false是 Vue 3 的条件泛型技巧——oldValue的类型会随options.immediate自动收窄不传immediate: true时为T[]传了则变为T[] | undefined。这保证了immediate模式下首次触发时oldValue为undefined的行为在类型层面也被正确表达。added与removed的类型不对称added: V即新值类型T[]中的元素集合removed: OV旧值类型。默认情况下二者都是T[]但该设计允许新旧值类型不同的边缘场景下依然类型安全。返回值WatchHandle与 Vue 的watch一致返回一个带stop()/pause()/resume()等方法的句柄组件卸载前若不依赖自动清理可用它手动停止监视。WatchOptionsImmediate即 Vue 原生 watch 的选项对象因此immediate、deep、flush: pre | post | sync均可用行为与原生watch完全一致watchArray只是在触发语义上做了增强。四、在 airi 仓库中的定位与版本事实watchArray并非 airi 自研 API而是仓库通过技能引导体系纳入的 VueUse 官方 API 参考。仓库中该文档的完整上下文如下技能引导入口.agents/skills/vueuse-functions/SKILL.md 是 airi 内置的VueUse 决策与实现指南其 Watch 分类表格中明确登记了FunctionDescriptionInvocationwatchArrayWatch for an array with additions and removalsAUTOAUTO调用规则意味着在 Vue 3 / Nuxt 3 项目中处理需要感知数组增删的需求时Agent 应自动优先选用该 composable而不是手写watch加手动 diff。SKILL.md 还要求使用任何函数时必须查阅./references中对应的文档获取 Usage 与 Type Declarations 细节本文主体所引用的 watchArray.md 正是这份被强制引用的参考文档。来源与同步信息.agents/skills/vueuse-functions/SYNC.md 标明该技能目录同步自上游vendor/vueuse/skills/vueuse-functionsGit SHAb6bb79b同步日期 2026-06-22说明文档内容与 VueUse 上游官方 API 保持一致可视为权威参考。依赖版本事实airi 通过 pnpm catalog 统一管理vueuse/core版本——pnpm-workspace.yaml 中 catalog 项为vueuse/core: ^14.4.0pnpm-lock.yaml 锁定解析到vueuse/core14.4.0配套vue3.5.41。各应用如apps/stage-web、apps/stage-pocket、apps/stage-tamagotchi、apps/component-calling等的package.json均通过vueuse/core: catalog:引用同一版本因此在 airi 任意一个 Vue 应用中import { watchArray } from vueuse/core均可直接使用无需各自安装。使用现状从仓库源码检索看当前代码中尚未出现对watchArray的直接调用vueuse/core的大量其他函数如useEventListener、useMagicKeys、useDeviceMotion等已在 stage-web、stage-pocket、stage-tamagotchi 等应用的组件与 composable 中被使用。可以推断watchArray属于该仓库技能体系为后续开发预置的随取随用候选 API——当出现按增量处理变化的数组需求时它是首选。五、典型适用场景与边界结合 airi 的多端应用形态watchArray的added/removed增量参数特别适合这类需求设备/权限清单变化驱动如音频输入设备列表、麦克风权限状态数组发生变化时只对新出现的项执行初始化、对消失的项执行资源释放而不是每次全量重建会话/消息集合的增量副作用聊天会话列表中新增会话时挂载对应 store、移除时清理缓存added/removed让副作用天然与 diff 一一对应配合onCleanup管理副作用生命周期在回调内注册清理函数保证下次触发或组件卸载时定时器、监听器被正确回收。使用边界同样明确若只关心值变了而不关心谁增谁删直接用原生watch即可watchArray的 diff 计算是额外的开销原地修改push/splice/下标赋值务必配{ deep: true }否则 watcher 不会触发需要防抖、节流、暂停等触发控制时可组合 VueUse 同目录下的watchDebounced、watchThrottled、watchPausable见 SKILL.md 的 Watch 分类但注意watchArray的增删 diff 语义只存在于它自身的回调参数中。六、小结watchArray是 VueUse 对 Vue 原生watch的一次精准增强保持WatchSource与WatchOptions的全部兼容性通过条件泛型正确处理immediate下的oldValue并在回调中直接交付added/removed增量把数组 diff 从业务代码收敛到框架层。在 airi 仓库中它由技能文档 watchArray.md 完整登记AUTO 调用规则版本经 pnpm catalog 锁定在 14.4.0可在 Web 与桌面各应用中一致使用。掌握引用替换免 deep、原地修改必 deep这一核心判据即可在响应式数组场景下正确、低成本地实现增量驱动的副作用逻辑。【免费下载链接】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),仅供参考