查看: 322|回复: 0

Vue3 customRef防抖验证与localStorage同步

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
customRef是Vue 3提供的高级响应式API,它允许开发者创建自定义ref对象,并完全控制依赖追踪和触发更新的时机。与普通ref相比,customRef在读取和赋值时可以插入自定义逻辑,因此适合防抖、验证、异步获取、本地存储同步等场景。

首先看customRef的基本结构。customRef接收一个工厂函数,工厂函数接收track和trigger两个参数,并返回包含get和set的对象。track在get中调用,用于收集依赖;trigger在set中调用,用于通知Vue值已变化。若get中缺少track,值变化时视图不会更新;若set中缺少trigger,赋值后不会触发重新渲染。

下面是一个最基础的自定义ref:
  1. import { customRef } from 'vue'
  2. const myCustomRef = customRef((track, trigger) => {
  3.   let value = 'initial value'
  4.   return {
  5.     get() {
  6.       track()
  7.       return value
  8.     },
  9.     set(newValue) {
  10.       value = newValue
  11.       trigger()
  12.     }
  13.   }
  14. })
复制代码

为什么需要customRef?因为普通ref赋值后立即触发视图更新,而业务中可能需要干预这个过程,比如输入防抖、节流、异步处理、数据验证、外部状态同步等。

场景一:防抖Ref。这是最经典用例,常用于搜索框。每次设置值时清除之前的定时器,延迟delay毫秒后再真正更新值和触发更新:
  1. import { customRef } from 'vue'
  2. function useDebouncedRef(initialValue, delay = 500) {
  3.   let timeoutId
  4.   let value = initialValue
  5.   return customRef((track, trigger) => {
  6.     return {
  7.       get() {
  8.         track()
  9.         return value
  10.       },
  11.       set(newValue) {
  12.         clearTimeout(timeoutId)
  13.         timeoutId = setTimeout(() => {
  14.           value = newValue
  15.           trigger()
  16.         }, delay)
  17.       }
  18.     }
  19.   })
  20. }
复制代码

组件里这样使用:const searchText = useDebouncedRef('', 500),再把 input 的 v-model 指向 searchText,停止输入500ms后才会更新视图。

场景二:带验证的Ref。在set中通过validator函数校验,合法才更新value,非法则把错误消息保存到error并触发更新:
  1. import { customRef } from 'vue'
  2. function useValidatedRef(initialValue, validator) {
  3.   let value = initialValue
  4.   let error = null
  5.   return customRef((track, trigger) => {
  6.     return {
  7.       get() {
  8.         track()
  9.         return { value, error }
  10.       },
  11.       set(newValue) {
  12.         const isValid = validator(newValue)
  13.         if (isValid === true) {
  14.           value = newValue
  15.           error = null
  16.         } else {
  17.           error = isValid
  18.         }
  19.         trigger()
  20.       }
  21.     }
  22.   })
  23. }
复制代码

使用时传入校验函数,例如校验年龄在0-120之间,非法时返回错误消息字符串。

场景三:LocalStorage同步Ref。读取初始值时优先从localStorage获取,set时同步写入localStorage,实现响应式数据与本地存储双向绑定:
  1. import { customRef } from 'vue'
  2. function useLocalStorageRef(key, initialValue) {
  3.   const storedValue = localStorage.getItem(key)
  4.   let value = storedValue ? JSON.parse(storedValue) : initialValue
  5.   return customRef((track, trigger) => {
  6.     return {
  7.       get() {
  8.         track()
  9.         return value
  10.       },
  11.       set(newValue) {
  12.         value = newValue
  13.         localStorage.setItem(key, JSON.stringify(newValue))
  14.         trigger()
  15.       }
  16.     }
  17.   })
  18. }
复制代码

比如const theme = useLocalStorageRef('theme', 'light'),修改theme.value时会自动同步到localStorage。

场景四:异步Ref。可以在set中触发API请求,并用loading和error状态辅助展示,请求完成后更新值:
  1. import { customRef } from 'vue'
  2. function useAsyncRef(asyncFetcher, initialValue = null) {
  3.   let value = initialValue
  4.   let loading = false
  5.   let error = null
  6.   return customRef((track, trigger) => {
  7.     return {
  8.       get() {
  9.         track()
  10.         return { value, loading, error }
  11.       },
  12.       async set(params) {
  13.         loading = true
  14.         error = null
  15.         trigger()
  16.         try {
  17.           const result = await asyncFetcher(params)
  18.           value = result
  19.         } catch (e) {
  20.           error = e
  21.         } finally {
  22.           loading = false
  23.           trigger()
  24.         }
  25.       }
  26.     }
  27.   })
  28. }
复制代码

customRef与普通ref的对比:普通ref依赖追踪自动、触发更新自动、灵活性低,适用常规状态管理;customRef需要手动调用track和trigger,可在get/set中插入任意逻辑,适合防抖、节流、异步、验证、外部同步等,但代码复杂度更高。

使用customRef的注意事项:第一,get中必须调用track,set中必须调用trigger,否则依赖收集或更新通知会失效。第二,避免在get或set中直接访问其他响应式对象的.value并立即触发更新,防止循环依赖。第三,内部状态通常用闭包保存,不要直接暴露value变量。第四,customRef控制力强但复杂度也高,普通ref、computed或watch能满足需求时优先使用它们。第五,customRef返回的对象与普通ref一样可以直接用于v-model绑定,所以很适合做防抖输入框等表单场景。

总结:customRef打破了默认响应式行为的限制,开发者通过track和trigger精确控制数据读取与更新时机,可以实现防抖、节流、异步处理、数据验证等功能,提升应用性能与用户体验。实际开发中建议将常用逻辑封装成Composable函数(Hooks),便于复用。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-2 14:04 , Processed in 0.020407 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部