Vue3 customRef 使用指南:学会自定义响应式引用
vue 3 的 customRef 是一个很有用的功能,它让我们可以创建自己想要的响应式数据。通过它,我们能够完全控制数据的读取和写入方式。这篇文章会详细介绍 customRef 的用法,帮助你理解如何在实际项目中使用它。
什么是 customRef?
customRef 是 Vue 3 提供的一个特殊函数,它可以创建一个自定义的响应式引用。与普通的 ref 不同,customRef 允许我们决定数据被读取和修改时会发生什么。
简单来说,customRef 就像是一个包装盒,你可以在盒子里设置自己的规则,决定别人如何查看和修改盒子里的东西。
customRef 的基本结构
customRef 接受一个函数作为参数,这个函数会收到两个重要的方法:track 和 trigger。
track:当数据被读取时调用,告诉 Vue 需要追踪这个数据的变化
trigger:当数据被修改时调用,通知 Vue 需要更新界面
这个函数需要返回一个包含 get 和 set 方法的对象:
import { customRef } from "vue";
const myRef = customRef((track, trigger) => {
let value = "初始值";
return {
get() {
track(); // 告诉 Vue 这个数据被读取了
return value;
},
set(newValue) {
value = newValue; // 更新数据
trigger(); // 告诉 Vue 数据变了,需要更新界面
}
};
});实际使用场景
1. 实现搜索框防抖
在搜索功能中,我们通常不希望用户每输入一个字符就立即搜索,这样会造成不必要的请求。使用 customRef 可以轻松实现防抖功能。
import { customRef } from "vue";
function useDebouncedRef(initialValue, delay = 500) {
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 searchText = useDebouncedRef("", 500);这样,只有当用户停止输入 500 毫秒后,搜索内容才会真正更新。
2. 处理异步数据
当我们需要从服务器获取数据时,customRef 可以帮助我们管理加载状态和错误信息。
import { customRef } from "vue";
function useAsyncRef(fetcher) {
return customRef((track, trigger) => {
let value = null;
let loading = false;
let error = null;
const loadData = async () => {
if (loading) return;
loading = true;
error = null;
trigger(); // 通知界面加载状态变了
try {
value = await fetcher();
} catch (err) {
error = err.message;
} finally {
loading = false;
trigger(); // 通知界面加载完成
}
};
return {
get() {
track();
// 如果还没有数据且不在加载中,就开始加载
if (value === null && !loading) {
loadData();
}
return { data: value, loading, error };
},
set(newValue) {
value = newValue;
trigger();
}
};
});
}
// 使用示例
const userInfo = useAsyncRef(() =>
fetch("/api/user/1").then(response => response.json())
);3. 数据验证
我们可以在数据被设置时进行验证,确保数据的正确性。
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) {
// 使用验证函数检查新值
const result = validator(newValue);
if (result === true) {
value = newValue;
error = null;
} else {
error = result; // 保存错误信息
}
trigger();
}
};
});
}
// 使用示例
const age = useValidatedRef(18, (value) => {
if (value < 0) return "年龄不能小于0";
if (value > 150) return "年龄不能大于150";
return true; // 表示验证通过
});在 Vue 组件中使用
下面是一个完整的组件示例,展示了如何在页面中使用上面创建的各种 customRef:
<template>
<div>
<!-- 防抖搜索框 -->
<div>
<h3>搜索框(带防抖)</h3>
<input v-model="searchText" placeholder="输入搜索内容..." />
<p>搜索内容:{{ searchText }}</p>
</div>
<!-- 异步数据 -->
<div>
<h3>用户信息</h3>
<div v-if="userInfo.loading">正在加载...</div>
<div v-else-if="userInfo.error">加载失败:{{ userInfo.error }}</div>
<div v-else>
<p>用户名:{{ userInfo.data?.name }}</p>
<p>邮箱:{{ userInfo.data?.email }}</p>
</div>
</div>
<!-- 数据验证 -->
<div>
<h3>年龄验证</h3>
<input v-model="age.value" type="number" />
<p v-if="age.error" style="color: red;">{{ age.error }}</p>
<p v-else>年龄:{{ age.value }}</p>
</div>
</div>
</template>
<script setup>
import { useDebouncedRef, useAsyncRef, useValidatedRef } from "./composables";
const searchText = useDebouncedRef("", 500);
const userInfo = useAsyncRef(() =>
fetch("https://jsonplaceholder.typicode.com/users/1").then(res => res.json())
);
const age = useValidatedRef(18, (value) => {
if (value < 0) return "年龄不能为负数";
if (value > 150) return "年龄不能超过150岁";
return true;
});
</script>需要注意的地方
使用 customRef 时,有几个重要点需要记住:
不要忘记调用 track 和 trigger
在 get 方法中必须调用 track()
在 set 方法中必须调用 trigger()
如果忘记调用,数据将不会正常响应变化
处理异步操作要小心
在 set 方法中进行异步操作时,要确保在适当的时候调用 trigger()
可以使用 Vue 的 nextTick 来确保界面正确更新
避免内存泄漏
如果使用了定时器或事件监听器,记得在不需要时清理它们
在组件销毁时,应该取消未完成的异步操作
常见问题解答
customRef 和 computed 有什么区别?
computed 用于基于其他数据计算出的值,而 customRef 用于需要完全控制读取和写入过程的情况。computed 的值是自动计算的,customRef 的值是由我们完全控制的。
可以在 customRef 中使用其他响应式数据吗?
可以,但需要确保在 get 方法中正确调用 track(),这样 Vue 才能追踪到依赖关系。
customRef 能处理嵌套对象吗?
默认情况下,customRef 不会深度追踪嵌套对象的变化。如果需要这个功能,你需要自己实现深度监听,或者结合使用 Vue 的 reactive。
总结
Vue 3 的 customRef 是一个强大而灵活的工具,它让我们能够创建符合特定需求的响应式数据。无论是实现防抖搜索、管理异步数据,还是添加数据验证,customRef 都能提供完美的解决方案。
通过将复杂的 customRef 逻辑封装成可重用的函数,我们可以让代码更加清晰和易于维护。虽然刚开始使用可能会觉得有些复杂,但一旦掌握,它将大大提升你处理复杂响应式逻辑的能力。
希望这篇文章能帮助你理解和应用 Vue 3 的 customRef 功能。在实际项目中多加练习,你会越来越熟练地使用这个强大的工具。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!