📖 概述
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 完全指南:自定義響應式引用的終極教程 - 高質量源碼分享平臺-免費下載各類網站源碼與模板及前沿技術分享