当前位置: 首页 > news >正文

Vue 3 customRef 完全指南:自定义响应式引用的终极教程

📖 概述

customRef() 是 Vue 3 中用于创建自定义响应式引用的组合式 API。它允许开发者完全控制响应式数据的读取和写入行为,为复杂的响应式逻辑提供了强大的灵活性。

🎯 基本概念

什么是 customRef?

customRef() 是一个工厂函数,它接受一个工厂函数作为参数,返回一个自定义的响应式引用。通过自定义 get 和 set 函数,可以实现复杂的响应式逻辑。

核心特性

特性描述
完全控制自定义 getter 和 setter 逻辑
延迟计算支持懒加载和缓存机制
副作用处理精确控制依赖收集和触发更新
类型安全完整的 TypeScript 支持

🔧 函数签名

function customRef<T>(factory: (track: () => void,trigger: () => void) => {get: () => T;set: (value: T) => void;}
): Ref<T>;

📋 参数说明

参数类型描述
track() => void依赖收集函数,在 getter 中调用
trigger() => void触发更新函数,在 setter 中调用

🎯 使用场景

1️⃣ 防抖输入框

创建带有防抖功能的输入框,避免频繁触发更新。

2️⃣ 异步数据加载

实现懒加载和缓存机制的响应式数据。

3️⃣ 数据验证和转换

在数据写入时进行验证和格式转换。

💻 代码示例

🚀 基础用法

import { customRef } from "vue";// 创建一个简单的自定义 ref
const count = customRef((track, trigger) => {let value = 0;return {get() {track(); // 收集依赖return value;},set(newValue) {value = newValue;trigger(); // 触发更新},};
});// 使用
console.log(count.value); // 0
count.value = 10;
console.log(count.value); // 10

⏱️ 防抖输入框

import { customRef } from "vue";function useDebouncedRef(initialValue, delay = 300) {return customRef((track, trigger) => {let value = initialValue;let timeoutId = null;return {get() {track();return value;},set(newValue) {clearTimeout(timeoutId);timeoutId = setTimeout(() => {value = newValue;trigger();}, delay);},};});
}// 在组件中使用
const searchQuery = useDebouncedRef("", 500);

🔄 异步数据加载

import { customRef } from "vue";function useAsyncRef(fetcher) {return customRef((track, trigger) => {let value = null;let loading = false;let error = null;const load = async () => {if (loading) return;loading = true;error = null;trigger();try {value = await fetcher();} catch (err) {error = err;} finally {loading = false;trigger();}};return {get() {track();if (value === null && !loading) {load();}return { value, loading, error };},set(newValue) {value = newValue;trigger();},};});
}// 使用示例
const userData = useAsyncRef(() =>fetch("/api/user").then((res) => res.json())
);

✅ 数据验证

import { customRef } from "vue";function useValidatedRef(initialValue, validator) {return customRef((track, trigger) => {let value = initialValue;let error = null;return {get() {track();return { value, error };},set(newValue) {try {const validationResult = validator(newValue);if (validationResult === true) {value = newValue;error = null;} else {error = validationResult;}} catch (err) {error = err.message;}trigger();},};});
}// 使用示例
const age = useValidatedRef(18, (value) => {if (value < 0) return "年龄不能为负数";if (value > 150) return "年龄不能超过150岁";return true;
});

🎨 在模板中使用

<template><div><!-- 防抖输入框 --><input v-model="searchQuery" placeholder="搜索..." /><p>搜索内容: {{ searchQuery }}</p><!-- 异步数据 --><div v-if="userData.loading">加载中...</div><div v-else-if="userData.error">错误: {{ userData.error }}</div><div v-else>{{ userData.value }}</div><!-- 数据验证 --><input v-model="age.value" type="number" /><p v-if="age.error" style="color: red;">{{ age.error }}</p></div>
</template><script setup>
import { useDebouncedRef, useAsyncRef, useValidatedRef } from "./composables";const searchQuery = useDebouncedRef("", 500);
const userData = useAsyncRef(() =>fetch("/api/user").then((res) => res.json())
);
const age = useValidatedRef(18, (value) => {if (value < 0) return "年龄不能为负数";return true;
});
</script>

⚠️ 注意事项

🔢 依赖收集和触发

  • ✅ 在 get() 函数中必须调用 track()
  • ✅ 在 set() 函数中必须调用 trigger()
  • ❌ 忘记调用会导致响应式失效

🕐 异步操作

  • ⚠️ 在 set() 中进行异步操作时要小心
  • 🔄 考虑使用 nextTick() 确保 DOM 更新

🧹 内存泄漏

  • 🗑️ 及时清理定时器和事件监听器
  • 🔄 在组件卸载时清理资源

🎯 最佳实践

1️⃣ 封装为组合式函数

将复杂的 customRef 逻辑封装为可复用的组合式函数。

2️⃣ 提供合理的默认值

为 customRef 提供合理的初始值,避免 undefined 状态。

3️⃣ 错误处理

在异步操作和验证逻辑中添加适当的错误处理。

4️⃣ 性能优化

避免在 getter 中进行昂贵的计算,考虑使用缓存机制。

❓ 常见问题

Q: customRef 和 computed 有什么区别?

A: customRef 提供完全的控制权,而 computed 是基于依赖的派生值。customRef 适合需要自定义 get/set 逻辑的场景。

Q: 可以在 customRef 中使用其他响应式数据吗?

A: 可以,但需要确保正确调用 track() 来收集依赖。

Q: customRef 是否支持深层响应式?

A: 默认不支持,需要手动处理嵌套对象的响应式。

📝 总结

customRef() 是 Vue 3 中实现复杂响应式逻辑的强大工具。它提供了完全的控制权,适用于防抖、本地存储同步、异步数据加载等场景。通过合理使用 track() 和 trigger() 函数,可以创建高效且灵活的响应式数据。在开发中,建议将复杂的 customRef 逻辑封装为组合式函数,以提高代码的可复用性和可维护性。

 Vue 3 customRef 完全指南:自定义响应式引用的终极教程 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿技术分享

http://www.dtcms.com/a/350087.html

相关文章:

  • 前端面试题vue合集
  • 华为云Stack环境中计算资源,存储资源,网络资源发放前的准备工作(中篇)
  • week4-[二维数组]平面上的点
  • win11中系统的WSL安装Centos以及必要组件
  • 基于 Prometheus+Alertmanager+Grafana 打造监控报警后台(一)-Prometheus介绍及安装
  • 企业级监控可视化系统 Prometheus + Grafana
  • 检索模型与RAG
  • 【Day 13】189.轮转数组
  • 项目文章|MeRIP-seq助力解析m6A RNA甲基化与康乃馨花衰老的调控机制
  • Day8--HOT100--160. 相交链表,206. 反转链表,234. 回文链表,876. 链表的中间结点
  • 30.throw抛异常
  • 项目前后端分离部署
  • LVM基本操作
  • LeetCode100-189轮转数组
  • 20.15 Hugging Face Whisper-large-v2中文微调实战:LoRA+混合精度单卡训练指南,3倍效率省90%显存
  • 正则表达式学习(基础)
  • AUTOSAR进阶图解==>AUTOSAR_RS_Features
  • 电脑隐私安全防护|快速清理Windows系统/浏览器/应用数据,支持文件粉碎与磁盘级擦除!
  • 从MyJUnit反思Java项目的工程实践(版本控制篇)
  • 数据库迁移幂等性介绍(Idempotence)(Flyway、Liquibase)ALTER、ON DUPLICATE
  • RabbitMQ面试精讲 Day 30:RabbitMQ面试真题解析与答题技巧
  • 深入解析MyBatis Mapper接口工作原理
  • Ubuntu24.04配置yolov5
  • 封装的form表单,校验规则(rules)只在提交时触发,为空时点击提交触发,再次输入内容也不显示校验规则(rules)
  • 机器学习】(12) --随机森林
  • Day27 进程管理(PCB、状态、调度、原语与资源管理)
  • pikachu之Over permission
  • 基于SpringBoot的宠物领养系统的设计与实现(代码+数据库+LW)
  • QML中的Connections
  • Vue 3 defineOptions 完全指南:让组件选项声明更现代化