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