Vue笔记(十五)--自定义引用

这一节了解一下Vue3 中的自定义引用,customRef是Vue3提供的一个响应式API,允许你自定义ref的get和set内部逻辑,通过track()收集依赖、trigger()触发更新,从而实现防抖等特殊行为。简单总结如下:

API:

customRef(factory):创建一个自定义的ref,传入一个工厂函数factory

factory 固定参数:track,trigger

track():收集依赖->当数据被模板/计算属性读取时,通知Vue收集当前副作用

trigger():派发更新 ->当数据修改完成后,通知所有收集到的依赖去更新视图

返回值:一个ref对象

场景:

1 防抖,输入框延迟更新,减少频繁请求

2 带本地持久化的ref:读写同时自动存入localStorage

3 读写拦截、数据校验

栗子:

TypeScript 复制代码
<template>
  <div>
    <input v-model="searchKey" placeholder="输入搜索内容" />
    <p>实时防抖结果:{{ searchKey }}</p>
  </div>
</template>

<script setup>
import { customRef } from 'vue'

function useDebounceRef(initValue, delay = 500) {
  let timer = null
  // customRef 工厂函数,接收 track、trigger
  return customRef((track, trigger) => {
    let value = initValue
    return {
      get() {
        track()
        return value
      },
      set(newVal) {
        clearTimeout(timer)
        timer = setTimeout(() => {
          value = newVal
          trigger()
        }, delay)
      }
    }
  })
}

// 使用自定义ref
const searchKey = useDebounceRef('')
</script>

Demo02

TypeScript 复制代码
<template>
  <div>
    <input v-model="username" placeholder="输入用户名" />
    <p>当前用户名:{{ username }}</p>
    <button @click="assignIllegal">赋值非法数字</button>
  </div>
</template>

<script setup>
import { customRef } from 'vue'

function useStorageRef(key, defaultValue) {
  return customRef((track, trigger) => {
    let value = localStorage.getItem(key) ?? defaultValue

    return {
      get() {
        console.log('[读取数据]', value)
        track() 
        return value
      },
      set(newVal) {
        console.log('[准备赋值]', newVal)
        if (typeof newVal !== 'string') {
          console.warn('赋值失败:数据类型不合法,只允许字符串!')
          return
        }
        value = newVal
        localStorage.setItem(key, value)
        trigger()
        console.log('[赋值成功并持久化]', value)
      }
    }
  })
}

// 使用自定义引用
const username = useStorageRef('user_name', '默认用户')

const assignIllegal = () => {
  username.value = 123456
}
</script>

原理:

customRef是一个高阶工厂函数,把ref内部的track(收集依赖)、trigger(触发更新)两个核心能力暴露给开发者,让我们手动控制什么时候收集依赖、什么时候派发更新,不再由Vue内部自动处理。

TypeScript 复制代码
开始调用 customRef(工厂函数)
        ↓
传入全局 track、trigger 给工厂函数
        ↓
执行工厂函数 → 得到 {get, set},闭包变量常驻
        ↓
返回 ref 实例(标记 __v_isRef = true)
------------------------------------------------------------------------------------------------
【读取 .value】
        ↓
执行 get()
        ↓
手动 track() → 收集当前effect依赖
        ↓
return 数据
------------------------------------------------------------------------------------------------
【修改 .value = newVal】
        ↓
执行 set(newVal)
        ↓
执行自定义业务逻辑(防抖/校验等等)
        ↓
 满足条件手动 trigger()
        ↓
取出收集的所有 effect 执行 → 视图更新、watch触发

注意:

1 get里面必须调用track(),否则模板不会收集依赖,视图不更新

2 set修改完数据必须调用trigger(),否则不会通知视图刷新

3 不要在get/set里面写无限循环逻辑

相关推荐
小羊斩肖恩1 小时前
具身智能的临界点:从数字幻觉走向物理真实的2026
1024程序员节
Sirens.1 小时前
网络通信基础:IP、端口、协议分层与数据封装
java·网络·网络协议·tcp/ip·java-ee·1024程序员节
Ruiery1 小时前
Linux 6.6内核并发与同步(一):原子操作与内存屏障 — 内核同步的硬件底座
linux·运维·服务器·1024程序员节
小冯不疯1 小时前
直播切片带货分账:3 类分成模型 × 4 道结算节点 × 2 类税务坑
1024程序员节
我是大猴子1 小时前
py how claude work项目分析
运维·服务器·windows·1024程序员节
Bug收容所1 小时前
Vue+JS Day3
前端·javascript·vue.js·前端框架·1024程序员节
码完就睡1 小时前
Linux——IP协议与路由选择
linux·网络·tcp/ip·1024程序员节
远航计算机1 小时前
收录从分钟级变 3 到 7 天,抢首发为什么失效了
大数据·人工智能·爬虫·chatgpt·aigc·1024程序员节
iDao技术魔方1 小时前
Bun v1.4.4 实战:用 bun fmt 替掉 prettier 的 5 个步骤
typescript·1024程序员节