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()}}))
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/67180.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

周末总结(2024/01/25)

工作 人际关系核心实践&#xff1a; 要学会随时回应别人的善意&#xff0c;执行时间控制在5分钟以内 坚持每天早会打招呼 遇到接不住的话题时拉低自己&#xff0c;抬高别人(无阴阳气息) 朋友圈点赞控制在5min以内&#xff0c;职场社交不要放在5min以外 职场的人际关系在面对利…

C++和Python实现SQL Server数据库导出数据到S3并导入Redshift数据仓库

用C实现高性能数据处理&#xff0c;Python实现操作Redshift导入数据文件。 在Visual Studio 2022中用C和ODBC API导出SQL Server数据库中张表中的所有表的数据为CSV文件格式的数据流&#xff0c;用逗号作为分隔符&#xff0c;用双引号包裹每个数据&#xff0c;字符串类型的数据…

基于OpenCV实现的答题卡自动判卷系统

一、图像预处理 🌄 二、查找答题卡轮廓 📏 三、透视变换 🔄 四、判卷与评分 🎯 五、主函数 六、完整代码+测试图像集 总结 🌟 在这篇博客中,我将分享如何使用Python结合OpenCV库开发一个答题卡自动判卷系统。这个系统能够自动从扫描的答题卡中提取信…

Android AOP:aspectjx

加入引用 在整个项目的 build.gradle 中&#xff0c;添加 classpath "com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10" 可以看到测试demo的 gradle 版本是很低的。 基于 github 上的文档&#xff0c;可以看到原版只支持到 gradle 4.4 。后续需要使…

第84期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

TCP/IP 协议:互联网通信的基石

TCP/IP 协议:互联网通信的基石 引言 TCP/IP协议,全称为传输控制协议/互联网协议,是互联网上应用最为广泛的通信协议。它定义了数据如何在网络上传输,是构建现代互联网的基础。本文将深入探讨TCP/IP协议的原理、结构、应用以及其在互联网通信中的重要性。 TCP/IP 协议概述…

蛇年特别版贪吃蛇H5小游戏

该作者的原创文章目录: 生产制造执行MES系统的需求设计和实现 企业后勤管理系统的需求设计和实现 行政办公管理系统的需求设计和实现 人力资源管理HR系统的需求设计和实现 企业财务管理系统的需求设计和实现 董事会办公管理系统的需求设计和实现 公司组织架构图设计工具 库存管…

MapReduce,Yarn,Spark理解与执行流程

MapReduce的API理解 Mapper 如果是单词计数&#xff1a;hello&#xff1a;1&#xff0c; hello&#xff1a;1&#xff0c; world&#xff1a;1 public void map(Object key, // 首字符偏移量Text value, // 文件的一行内容Context context) // Mapper端的上下文&#xff0c;…

如何将xps文件转换为txt文件?xps转为pdf,pdf转为txt,提取pdf表格并转为txt

文章目录 xps转txt方法一方法二 pdf转txt整页转txt提取pdf表格&#xff0c;并转为txt 总结另外参考XPS文件转换为TXT文件XPS文件转换为PDF文件PDF文件转换为TXT文件提取PDF表格并转为TXT示例代码&#xff08;部分&#xff09; 本文测试代码已上传&#xff0c;路径如下&#xff…

Day26-【13003】短文,什么是顺序表?顺序表和数组、内存地址的关系?顺序表的插入、删除操作如何实现?操作的时间复杂度是多少?

文章目录 第二节&#xff0c;线性表的顺序存储及实现概览什么是顺序表和链表&#xff1f;顺序存储的叫顺序表顺序表和数组还有内存地址的关系&#xff1f;顺序表的基本操作如何实现&#xff1f;1、插入操作如何实现&#xff1f;2、删除操作如何实现&#xff1f;3、赋值和查找操…

【含开题报告+文档+PPT+源码】基于SpringBoot的校园跑腿管理系统

开题报告 本文旨在探讨校园跑腿系统的设计与实现&#xff0c;通过深入研究与分析&#xff0c;实现了一套包含用户管理、发布跑腿单、跑腿抢单、跑腿单评论、在线留言以及用户在线充值等功能的综合性系统。该系统以提高校园内物品跑腿与配送效率为核心目标&#xff0c;为广大学…

zookeeper的介绍和简单使用

1 zookerper介绍 zookeeper是一个开源的分布式协调服务&#xff0c;由Apache软件基金会提供&#xff0c;主要用于解决分布式应用中的数据管理、状态同步和集群协调等问题。通过提供一个高性能、高可用的协调服务&#xff0c;帮助构建可靠的分布式系统。 Zookeeper的特点和功能…

二级 二维数组3

对角线之和 题目描述 输入一个矩阵&#xff0c;输出右上-左下对角线上的数字和 输入 输入1个整数N。(N<10)表示矩阵有n行n列 输出 对角线的和 样例 输入复制 4 1 2 3 4 2 3 4 5 4 5 6 7 1 2 3 4 输出复制 14 #include<iostream> using namespace std; int main() {i…

Spring Boot MyBatis Plus 版本兼容问题(记录)

Spring Boot & MyBatis Plus 版本兼容问题&#xff08;Invalid value type for attribute factoryBeanObjectType: java.lang.String&#xff09; 问题描述问题排查1. 检查 MapperScan 的路径2. 项目中没有配置 FactoryBean3. 检查 Spring 和 MyBatis Plus 版本兼容性 解决…

嵌入式学习笔记-杂七杂八

文章目录 连续波光纤耦合激光器工作原理主要特点应用领域设计考虑因素 数值孔径&#xff08;Numerical Aperture&#xff0c;简称NA&#xff09;数值孔径的定义数值孔径的意义数值孔径的计算示例数值孔径与光纤 四象限探测器检测目标方法四象限划分检测目标的步骤1. 数据采集2.…

Java Web-Cookie与Session

会话跟踪技术 会话跟踪技术是一种在 Web 应用程序中跟踪用户会话状态的机制&#xff0c;它允许服务器在多个请求之间识别和关联属于同一用户的请求&#xff0c;以便在整个会话过程中保持用户相关的信息。以下是几种常见的会话跟踪技术&#xff1a; Cookie 概念&#xff1a;Cook…

Spring Boot - 数据库集成04 - 集成Redis

Spring boot集成Redis 文章目录 Spring boot集成Redis一&#xff1a;redis基本集成1&#xff1a;RedisTemplate Jedis1.1&#xff1a;RedisTemplate1.2&#xff1a;实现案例1.2.1&#xff1a;依赖引入和属性配置1.2.2&#xff1a;redisConfig配置1.2.3&#xff1a;基础使用 2&…

STM32使用VScode开发

文章目录 Makefile形式创建项目新建stm项目下载stm32cubemx新建项目IED makefile保存到本地arm gcc是编译的工具链G++配置编译Cmake +vscode +MSYS2方式bilibiliMSYS2 统一环境配置mingw32-make -> makewindows环境变量Cmake CmakeListnijia 编译输出elfCMAKE_GENERATOR查询…

Oracle 12c 中的 CDB和PDB的启动和关闭

一、简介 Oracle 12c引入了多租户架构&#xff0c;允许一个容器数据库&#xff08;Container Database, CDB&#xff09;托管多个独立的可插拔数据库&#xff08;Pluggable Database, PDB&#xff09;。本文档旨在详细描述如何启动和关闭CDB及PDB。 二、容器数据库 (CDB) 2.1…

网络仿真工具Core环境搭建

目录 安装依赖包 源码下载 Core安装 FAQ 下载源码TLS出错误 问题 解决方案 找不到dbus-launch 问题 解决方案 安装依赖包 调用以下命令安装依赖包 apt-get install -y ca-certificates git sudo wget tzdata libpcap-dev libpcre3-dev \ libprotobuf-dev libxml2-de…