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里面写无限循环逻辑

相关推荐
YLCHUP2 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
旖旎夜光4 小时前
【C++ 基础入门】C++11 新特性(中):右值引用、移动语义与完美转发
开发语言·c++·笔记·学习
普通人65 小时前
WebGL与WebGPU入门指南
开发语言·webgl·1024程序员节
星恒随风14 小时前
MySQL 从零入门(五):MySQL 内置函数详解——日期、字符串、数学函数与实战案例
linux·数据库·笔记·sql·mysql
2603_9696948517 小时前
【JavaWeb学习记录】MyBatis核心知识点与实战笔记:从入门到动态SQL
笔记·sql·学习·mysql·mybatis·javaweb·学习方法
可乐ea17 小时前
智能体记忆该拆成几层:笔记、记忆表示与注入上下文
服务器·数据库·笔记·ai智能体·提示词工程·上下文工程·记忆系统
Go Work21 小时前
两个等值条件摆着,MySQL 偏要全表扫
经验分享·笔记
猫猫不是喵喵.21 小时前
从0到1创建一个微服务项目
java·数据库·微服务·1024程序员节
Oll Correct21 小时前
Adobe illustrator 案例十四:花元素标志草图绘制
笔记·ui·adobe·illustrator
每月一号准时摆烂1 天前
服务器运维笔记(一)——使用shell编写实时查看BMC功率的脚本
运维·服务器·笔记