
airi 仓库中的 VueUse usePrevious捕获 ref 上一次取值的技术详解【免费下载链接】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/airiusePrevious是 VueUsevueuse/core提供的工具型 composable用于持有某个 ref 的上一次值previous value。在 airi 这类基于 Vue 3 构建的多端实时语音伴侣项目中vueuse/core通过 pnpm catalog 以^14.4.0版本统一分发到各应用与包见 pnpm-workspace.yaml 中的 catalog 声明并被 packages/stage-ui/package.json、apps/stage-web/package.json 等以vueuse/core: catalog:的方式引用。airi 的 Agent 技能库中专门维护了 VueUse 函数速查集 vueuse-functions SKILL.md其中将usePrevious归入 Utilities 分类标记为AUTO调用级别即适用时可直接使用其详细参考文档即 usePrevious.md该技能集来自 vendored VueUse skills 的同步副本同步元数据见 SYNC.md。读完本文你能掌握usePrevious的两种重载签名、undefined初始语义与浅引用返回类型并理解它在 Vue 响应式体系中的正确用法与适用边界。功能定位为什么要记住上一个值很多 UI 与逻辑场景需要对比当前值与上一个值典型如显示值从 A 变为 B的变更提示diff 展示、状态过渡动画根据变化方向增大/减小触发不同逻辑例如音量、窗口尺寸变化的箭头指示在多步向导、表单校验中比较上一步输入与本步输入。如果没有usePrevious开发者通常要手写一个 ref 并在watch回调中先保存旧值再更新新值样板代码多且容易在immediate、deep等细节上出错。usePrevious把这一模式收敛成一行调用。基础用法从文档示例看行为语义usePrevious.md 给出的官方用法示例如下import { usePrevious } from vueuse/core import { shallowRef } from vue const counter shallowRef(Hello) const previous usePrevious(counter) console.log(previous.value) // undefined counter.value World console.log(previous.value) // Hello从该示例可以提炼出三条核心行为首取值之前返回undefinedcounter刚建立、尚未发生任何变化时previous.value为undefined因为上一个值在时间线上尚不存在。变化发生后同步回填当counter.value被赋值为World时previous立即持有变化前的值Hello。由于 Vue 的 watch 默认在变更被侦测到的时机同步更新内部状态模板与后续代码读到的就是旧值。接受 ref 类输入示例中使用shallowRef而类型签名表明入参实际上是MaybeRefOrGetterT见下文即普通值、ref、computed、getter 函数均可传入。在 airi 的页面组件如 apps/stage-web/src/pages/index.vue、apps/stage-tamagotchi/src/renderer/pages/index.vue 等大量 Vue SFC 中已广泛使用vueuse/core的 composable中usePrevious属于同类工具链的一员需要旧值语义时优先选用它而不是手写 watch 保存旧值。类型声明两个重载与返回类型参考文档给出的完整类型声明如下引自 usePrevious.md/** * Holds the previous value of a ref. */ export declare function usePreviousT( value: MaybeRefOrGetterT, ): ReadonlyShallowRefT | undefined export declare function usePreviousT( value: MaybeRefOrGetterT, initialValue: T, ): ReadonlyShallowRefT逐项解读入参value: MaybeRefOrGetterT这是 Vue 响应式体系中的可解引用输入类型统一接受原始值T、RefT、ComputedRefT以及 getter() T。这使usePrevious可以无缝套用在任何响应式来源之上包括computed与shallowRef。返回ReadonlyShallowRefT | undefined无初始值重载ShallowRef表明该 ref 是浅层的——它只对引用本身被替换敏感不会递归追踪对象内部属性。对于对象值比较/展示的是引用切换这一事实若需要追踪深层属性变化应结合watch(..., { deep: true })自行处理或让上游 ref 本身具备相应深度。类型上为T | undefined与首取前为undefined的运行时行为严格对应。initialValue: T重载提供第二个参数即可把未变化状态从undefined替换为你指定的初始值此时返回类型收紧为ReadonlyShallowRefT消费端不再需要处理undefined分支。例如usePrevious(mode, idle)在首次变化前会得到idle而不是undefined对联合字面量类型如状态机枚举尤其友好。Readonly返回的 ref 只读调用方只能消费previous.value不能反向写入——这也从类型层面杜绝了把 previous 当状态源修改的反模式。进阶用法示例1. 配合initialValue消除 undefined 分支import { ref } from vue import { usePrevious } from vueuse/core type Stage idle | speaking | listening const stage refStage(idle) const prevStage usePrevious(stage, idle) // prevStage.value 的类型是 Stage永远不会是 undefined function transitionLabel() { return ${prevStage.value} - ${stage.value} }2. 传入 computed / getter而非只能传 refimport { computed, ref } from vue import { usePrevious } from vueuse/core const volume ref(0.5) const isLoud computed(() volume.value 0.8) const wasLoud usePrevious(isLoud) // 音量从大降到小的那一刻wasLoud.value 仍为 true由于入参是MaybeRefOrGetterT任何由原始状态派生出的响应式值都可以被追踪上一次状态。3. 与 watch 组合实现变化方向判断import { ref, watch } from vue import { usePrevious } from vueuse/core const windowWidth ref(window.innerWidth) const prevWidth usePrevious(windowWidth, 0) watch(windowWidth, (now, old) { // 与 previous 交叉验证方向 const direction now (prevWidth.value || old) ? enlarge : shrink console.log(direction) })4. 与同族工具的关系在 airi 技能库的 State 分类中还有useRefHistory、useManualRefHistory等历史追踪工具见 SKILL.md 的 State 表格。usePrevious只保留最近一次这一个历史点开销最小需要完整 undo/redo 历史时再升级到useRefHistory两者定位互补。适用边界与注意事项同步赋值场景之外previous的更新依赖 Vue 的侦测机制。如果在同一微任务中连续多次同步赋值且未触发侦测刷新读取到的上一个值以实际 watch 触发为准对高频变化如每帧更新建议先做节流可参考同仓库 Utilities 分类中的useThrottleFn再喂给usePrevious。浅层语义返回的是ShallowRef对象值引用不变而内部字段变化时previous不会响应这类需求应让上游 ref 用ref()深层或显式 watch deep。SSR 环境airi 的多端形态Web / Electron / Capacitor 容器参见 apps/stage-web 与 apps/stage-tamagotchi中usePrevious纯内存、不触碰浏览器 APISSR 首帧会得到undefined或initialValue行为可预期。只读约定不要尝试写previous.value x类型层面是Readonly语义上也应当把previous只用作展示/对比源。在 airi 仓库中如何查阅与使用参考文档含官方示例与类型声明usePrevious.md函数索引与调用级别AUTOSKILL.md Utilities 表格依赖版本基线pnpm catalog 中vueuse/core为^14.4.0pnpm-workspace.yaml各子包以catalog:引用引入方式import { usePrevious } from vueuse/core无额外运行时依赖属于 core 包内置功能小结usePrevious用一行调用解决了记住 ref 上一个值这一常见模式无初始值重载返回ReadonlyShallowRefT | undefined首次读取为undefined带initialValue重载可消除 undefined 分支并收紧类型。其入参MaybeRefOrGetterT让它可挂在 ref、computed 与 getter 上ShallowRef返回值则明确了浅层追踪的语义边界。在 airi 以vueuse/core ^14.4.0统一管理的 VueUse 工具链中它是实现状态对比、变化方向判断与轻量 diff 展示的首选工具。【免费下载链接】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),仅供参考