欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 幼教 > vue3中customRef的用法以及使用场景

vue3中customRef的用法以及使用场景

2025/2/24 19:18:10 来源:https://blog.csdn.net/qq_34645412/article/details/145369729  浏览:    关键词:vue3中customRef的用法以及使用场景

1. 基本概念

customRef 是 Vue3 提供的用于创建自定义响应式引用的 API,允许显式地控制依赖追踪和触发响应。它返回一个带有 getset 函数的工厂函数来自定义 ref 的行为。

1.1 基本语法

import { customRef } from 'vue'function createCustomRef(value) {return customRef((track, trigger) => {return {get() {track() // 追踪依赖return value},set(newValue) {value = newValuetrigger() // 触发更新}}})
}

2. 常见使用场景

2.1 防抖 Ref

function useDebouncedRef(value, delay = 200) {let timeoutreturn customRef((track, trigger) => {return {get() {track()return value},set(newValue) {clearTimeout(timeout)timeout = setTimeout(() => {value = newValuetrigger()}, delay)}}})
}// 使用示例
const searchQuery = useDebouncedRef('', 500)// 在模板中使用
// <input v-model="searchQuery" />

2.2 节流 Ref

function useThrottledRef(value, delay = 200) {let lastTriggerTime = 0return customRef((track, trigger) => {return {get() {track()return value},set(newValue) {const now = Date.now()if (now - lastTriggerTime >= delay) {value = newValuelastTriggerTime = nowtrigger()}}}})
}// 使用示例
const scrollPosition = useThrottledRef(0, 100)

2.3 验证 Ref

function useValidatedRef(value, validator) {return customRef((track, trigger) => {return {get() {track()return value},set(newValue) {if (validator(newValue)) {value = newValuetrigger()} else {console.warn('Invalid value:', newValue)}}}})
}// 使用示例
const age = useValidatedRef(18, (value) => {return Number.isInteger(value) && value >= 0 && value <= 120
})

2.4 异步 Ref

function useAsyncRef(getter) {let value = nulllet isLoading = trueconst ref = customRef((track, trigger) => {// 初始加载数据getter().then(data => {value = dataisLoading = falsetrigger()})return {get() {track()return { value, isLoading }},set() {throw new Error('Async ref is readonly')}}})return ref
}// 使用示例
const userProfile = useAsyncRef(async () => {const response = await fetch('/api/user')return response.json()
})

3. 高级应用场景

3.1 持久化 Ref

function useLocalStorageRef(key, defaultValue) {const storedValue = JSON.parse(localStorage.getItem(key) || 'null')let value = storedValue !== null ? storedValue : defaultValuereturn customRef((track, trigger) => {return {get() {track()return value},set(newValue) {value = newValuelocalStorage.setItem(key, JSON.stringify(newValue))trigger()}}})
}// 使用示例
const theme = useLocalStorageRef('app-theme', 'light')

3.2 格式化 Ref

function useFormattedRef(value, formatter, parser) {return customRef((track, trigger) => {return {get() {track()return formatter(value)},set(newValue) {value = parser(newValue)trigger()}}})
}// 使用示例
const price = useFormattedRef(1000,(value) => `$${value.toFixed(2)}`,(value) => parseFloat(value.replace('$', ''))
)

4. 实际应用示例

4.1 表单输入处理

<template><div><input v-model="email" /><p>状态: {{ email.status }}</p><p>错误信息: {{ email.error }}</p></div>
</template><script setup>
function useValidatedEmailRef(initialValue = '') {let value = initialValuelet status = 'initial'let error = ''const validateEmail = (email) => {const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/return regex.test(email)}return customRef((track, trigger) => {return {get() {track()return {value,status,error}},set(newValue) {value = newValueif (!newValue) {status = 'initial'error = ''} else if (validateEmail(newValue)) {status = 'valid'error = ''} else {status = 'invalid'error = '请输入有效的邮箱地址'}trigger()}}})
}const email = useValidatedEmailRef()
</script>

4.2 搜索优化

<template><div><input v-model="searchQuery" /><div v-if="searchQuery.isLoading">加载中...</div><ul v-else><li v-for="result in searchQuery.results" :key="result.id">{{ result.title }}</li></ul></div>
</template><script setup>
function useSearchRef(initialValue = '') {let value = initialValuelet results = []let isLoading = falseconst performSearch = async (query) => {if (!query) {results = []return}isLoading = truetry {const response = await fetch(`/api/search?q=${query}`)results = await response.json()} catch (error) {console.error('Search failed:', error)results = []} finally {isLoading = false}}return customRef((track, trigger) => {return {get() {track()return {value,results,isLoading}},set(newValue) {value = newValueperformSearch(newValue).then(() => trigger())}}})
}const searchQuery = useSearchRef()
</script>

5. 最佳实践

5.1 性能优化

// 避免不必要的触发
function useOptimizedRef(value) {return customRef((track, trigger) => {return {get() {track()return value},set(newValue) {// 只在值真正改变时触发更新if (value !== newValue) {value = newValuetrigger()}}}})
}

5.2 错误处理

function useSafeRef(value, errorHandler = console.error) {return customRef((track, trigger) => {return {get() {try {track()return value} catch (error) {errorHandler(error)return null}},set(newValue) {try {value = newValuetrigger()} catch (error) {errorHandler(error)}}}})
}

6. 注意事项

  1. 避免过度使用
// ❌ 不要为简单的值使用 customRef
const simpleValue = customRef((track, trigger) => ({get() {track()return value},set(newValue) {value = newValuetrigger()}
}))// ✅ 使用普通的 ref
const simpleValue = ref(value)
  1. 保持响应性
// 确保在需要的时候调用 track 和 trigger
function useCustomRef(value) {return customRef((track, trigger) => ({get() {track() // 不要忘记 trackreturn value},set(newValue) {value = newValuetrigger() // 不要忘记 trigger}}))
}
  1. 内存管理
// 清理副作用
function useCustomRef(value) {let cleanup = nullreturn customRef((track, trigger) => ({get() {track()return value},set(newValue) {// 清理之前的副作用if (cleanup) {cleanup()}value = newValue// 设置新的副作用cleanup = setupSideEffect(value)trigger()}}))
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词