📖 概述

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

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

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

相关文章

Java项目-苍穹外卖_Day1

项目来源&#xff1a; 【黑马程序员 Java项目实战《苍穹外卖》】 [https://www.bilibili.com/video/BV1TP411v7v6] ZZHow(ZZHow1024) 软件开发整体介绍 软件开发流程 需求分析&#xff1a;需求规格说明书、产品原型。设计&#xff1a;UI 设计、数据库设计、接口设计。编码…

面试可能问到的问题思考-MySQL

MySQL 1. 数据库与缓存的一致性 引入缓存&#xff0c;因为缓存只是数据库数据的副本&#xff0c;那么就可能存在副本和原数据不一致的情况 一致性 ACID里面的C&#xff0c;和CAP中的C不是一个概念&#xff0c;虽然都叫一致性。CAP中的C&#xff0c;指的是多个副本之间逻辑上…

【Java】 Spring Security 赋能 OAuth 2.0:构建安全高效的现代认证体系

还在为高昂的AI开发成本发愁?这本书教你如何在个人电脑上引爆DeepSeek的澎湃算力! 在当今数字化时代,认证与授权已成为应用系统安全的核心。OAuth 2.0 作为一种开放标准协议,广泛应用于第三方授权场景中,而 Spring Security 则提供了强大的框架支持来实现这一协议。本文深…

实际工作几月后常用相关命令笔记记录

目前&#xff0c;我这只工程师幼崽经历几个月的工作&#xff0c;不能说是收获很多&#xff0c;也算是成长经验1吧。主要工作后才知道好多东西都是自己不会的不了解的&#xff0c;但是工作需要不一定自己完全吃透&#xff0c;在合适的地方正确的使用一般情况就ok了&#xff0c;所…

突破传统文本切片的瓶颈:AntSK-FileChunk语义切片技术详解前言:为什么我们需要重新思考文本切片?

在当今大语言模型&#xff08;LLM&#xff09;应用蓬勃发展的时代&#xff0c;我们面临着一个看似简单却至关重要的问题&#xff1a;如何有效地处理长文本&#xff1f;无论是构建知识库、实现RAG&#xff08;检索增强生成&#xff09;系统&#xff0c;还是进行文档智能分析&…

LeetCode-542. 01 矩阵

1、题目描述给定一个由 0 和 1 组成的矩阵 mat &#xff0c;请输出一个大小相同的矩阵&#xff0c;其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。两个相邻元素间的距离为 1 。示例 1&#xff1a;输入&#xff1a;mat [[0,0,0],[0,1,0],[0,0,0]] 输出&#xff1a;[[…

Elasticsearch如何确保数据一致性?

Elasticsearch 通过多种机制确保数据在分布式环境中的一致性&#xff0c;但由于其分布式和近实时&#xff08;Near Real-Time, NRT&#xff09;的特性&#xff0c;它提供的是最终一致性&#xff08;Eventual Consistency&#xff09;&#xff0c;而非强一致性。以下是核心机制和…

2026毕设选题-大数据-基于 Spring Boot的化妆品推荐系统的设计与实现

技术范围&#xff1a;大数据、物联网、SpringBoot、Vue、SSM、HLMT、小程序、PHP、Nodejs、Python、爬虫、数据可视化、安卓App、机器学习等设计与开发。 主要内容&#xff1a;功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文降重、长…

数据结构算法:顺序表

数据结构&#xff1a;顺序表一.寄包柜1.题目如何创建数组&#xff1f;1. 需求本质2. 传统静态数组的缺陷3. 动态方案&#xff1a;向量的数组4. 核心逻辑5. 关键优势总结2.解题思路2.1题目分析2.2具体解题逻辑拆解步骤2.3总结2.4参考代码二.移动零1.题目2.解题思路2.1**解题核心…

IIS 安装了.netcore运行时 还是报错 HTTP 错误 500.19

IIS 安装了.netcore运行时 还是报错 HTTP 错误 500.19 - Internal Server Error 错误代码 0x8007000d 我甚至是先安装的SDK&#xff0c;再安装的运行时runtime的安装包&#xff0c;都不行。 而且在IIS的模块中&#xff0c;找不到 AspNetCoreModuleV2。 最后在微软官网n…

Flink 滑动窗口实战:从 KeyedProcessFunction 到 AggregateFunction WindowFunction 的完整旅程

一、业务背景 我们要在 Flink 实时流上统计 每个用户-品牌组合最近 1 小时的最晚行为时间&#xff0c;并且每 5 分钟更新一次结果。 数据来自 Kafka&#xff0c;事件类型为 CartEvent&#xff1a; public class CartEvent {public String userId;public String brandId;public …

Kubernetes“城市规划”指南:告别资源拥堵与预算超支,打造高效云原生都市

导读&#xff1a; 如果把你的Kubernetes集群想象成一座拔地而起的现代化大都市&#xff0c;那么你&#xff0c;平台工程师&#xff0c;就是这座城市的首席规划师。然而&#xff0c;为何我们精心打造的许多“云原生都市”正迅速陷入交通拥堵、资源闲置和预算超支的困境&#xff…

2.4 Flink运行时架构:Task、SubTask、ExecutionGraph的关系

在理解Flink运行时架构之前&#xff0c;我们先用一个生活化的比喻来建立直观认识&#xff1a; 想象你是一家大型工厂的总经理&#xff0c;需要生产一批复杂的产品。你会怎么做&#xff1f; 制定生产计划&#xff1a;首先画出生产流程图&#xff0c;明确每个环节的工作内容分解任…

`mysql_query()` 数据库查询函数

1) 函数的概念与用途 mysql_query() 是 MySQL C API 中的核心函数&#xff0c;用于向 MySQL 服务器发送 SQL 查询语句。这个函数充当了 C/C 应用程序与 MySQL 数据库之间的桥梁&#xff0c;允许程序执行各种数据库操作。 可以将 mysql_query() 想象成一个"数据库信使"…

[系统架构设计师]通信系统架构设计理论与实践(十七)

[系统架构设计师]通信系统架构设计理论与实践&#xff08;十七&#xff09; 一.通信系统网络架构 形式: 局域网&#xff0c;广域网&#xff0c;移动通信网 1.局域网网络架构 单一机构专用计算机的网络 组成&#xff1a;计算机&#xff0c;交换机&#xff0c;路由器 特点&#x…

【赵渝强老师】Docker的私有镜像仓库:Harbor

Harbor是由VMware公司开发并开源的企业级的Docker镜像仓库的管理项目&#xff0c;它包括镜像的权限管理&#xff08;RBAC&#xff09;、目录访问&#xff08;LDAP&#xff09;、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。 视频讲解如下 【赵渝强老师】Docker的…

【QT/C++】实例理解类间的六大关系之泛化关系(Generalization)

【QT/C】实例理解类间的六大关系之泛化关系&#xff08;Generalization&#xff09; 在前面章节一文完美概括UML类图及其符号&#xff08;超详细介绍&#xff09;中已经对泛化关系的概念进行了总结&#xff0c;本文我将用实际案例来进一步理解泛化关系&#xff0c;以便应对未来…

【微服务的数据一致性分发问题】究极解决方案

文章目录一、微服务数据分发1、简介2、典型场景&#xff08;1&#xff09;跨服务业务流程协同&#xff08;2&#xff09;数据副本同步&#xff08;读写分离&#xff09;&#xff08;3&#xff09;实时状态通知&#xff08;4&#xff09;数据聚合与统计分析&#xff08;5&#x…

挖币与区块链技术有怎样的联系?

挖币&#xff08;通常指加密货币挖矿&#xff09;与区块链技术有着紧密的联系&#xff0c;挖矿是区块链网络维持运行和安全的重要机制之一&#xff0c;具体联系如下&#xff1a;1. 挖矿是区块链共识机制的核心环节区块链通过“共识机制”确保全网节点对交易记录达成一致&#x…

C数据结构:二叉树(下)

C数据结构&#xff1a;二叉树&#xff08;下&#xff09; 1.二叉树递归结构遍历 2.例题 3.二叉树的性质 1.二叉树递归结构遍历 我们先创建一个如下图所示的二叉树。typedef int BTDataType; typedef struct BinaryTreeNode {BTDataType data;struct BinaryTreeNode* left;struc…