Vue3 Ref全家桶深度解析:掌握响应式编程精髓

news2025/2/11 20:28:34

Vue3 Ref全家桶深度解析:掌握响应式编程精髓

一、Ref核心概念

1.1 响应式数据容器

const count = ref(0)
// 相当于创建了一个响应式容器:
{
  value: 0,
  __v_isRef: true,
  // 其他响应式系统属性
}

1.2 全家桶全景图

Ref核心
基础响应
浅层响应
自定义响应
引用转换
工具函数
ref
shallowRef
customRef
toRef
toRefs
isRef
unref

二、基础Ref体系

2.1 ref - 深响应式

// 创建响应式引用
const user = ref({
  name: 'Alice',
  profile: {
    age: 25,
    hobbies: ['reading', 'coding']
  }
})

// 深层修改自动触发更新
user.value.profile.hobbies.push('gaming')

2.2 shallowRef - 浅层响应

const bigObject = shallowRef({
  layer1: { 
    layer2: { 
      data: '原始值'
    }
  }
})

// 直接修改.value触发响应
bigObject.value = { ... }// 深层修改不会触发
bigObject.value.layer1.layer2.data = '新值'

实战场景

// 处理第三方库实例
const mapInstance = shallowRef(null)

onMounted(() => {
  mapInstance.value = new ThirdPartyMap() // 初始化后触发响应
})

三、高级Ref定制

3.1 customRef - 自定义响应逻辑

function useStorageRef(key, defaultValue) {
  return customRef((track, trigger) => ({
    get() {
      track()
      const value = localStorage.getItem(key)
      return value ? JSON.parse(value) : defaultValue
    },
    set(newValue) {
      localStorage.setItem(key, JSON.stringify(newValue))
      trigger()
    }
  }))
}

// 使用示例
const userSettings = useStorageRef('settings', { theme: 'light' })

3.2 防抖搜索实战

function useDebouncedRef(initialValue, delay = 300) {
  let timeout
  return customRef((track, trigger) => ({
    get() {
      track()
      return initialValue
    },
    set(newValue) {
      clearTimeout(timeout)
      timeout = setTimeout(() => {
        initialValue = newValue
        trigger()
      }, delay)
    }
  }))
}

四、Ref转换体系

4.1 toRef - 保持响应连接

const state = reactive({ count: 0 })
const countRef = toRef(state, 'count')

countRef.value++ // state.count 同步变为1

4.2 toRefs - 解构响应对象

<script setup>
function usePosition() {
  const pos = reactive({ x: 0, y: 0 })
  return { 
    ...toRefs(pos),
    reset: () => { pos.x = pos.y = 0 }
  }
}

const { x, y } = usePosition()
</script>

<template>
  <div>X: {{ x }}, Y: {{ y }}</div>
</template>

4.3 响应式Props处理

const props = defineProps(['user'])
const userRef = toRef(props, 'user')

watch(userRef, (newVal) => {
  console.log('用户信息更新:', newVal)
})

五、Ref工具函数

5.1 isRef - 类型检查

const maybeRef = ref(0)
console.log(isRef(maybeRef)) // true
console.log(isRef({ value: 0 })) // false

// 类型守卫用法
function handleValue(input) {
  if (isRef(input)) {
    console.log(input.value)
  } else {
    console.log(input)
  }
}

5.2 unref - 智能取值

const a = ref(10)
const b = 20

console.log(unref(a)) // 10
console.log(unref(b)) // 20

// 在组合式函数中的妙用
function useSmartLogger(value) {
  const val = unref(value)
  console.log('当前值:', val)
}

// 可以接受ref或普通值
useSmartLogger(a) // 10
useSmartLogger(b) // 20

六、全家桶对比指南

API核心功能典型应用场景注意事项
ref创建深响应式引用基本类型/对象/数组需要.value访问
shallowRef创建浅层响应式引用大对象/类实例/第三方库实例深层修改需手动触发
customRef自定义响应式容器防抖/节流/本地存储集成需要手动track/trigger
toRef保持源响应式连接从reactive对象提取属性源属性必须存在
toRefs解构响应式对象组合式函数返回值/Props解构保持响应式连接
isRef检测Ref对象类型检查/条件处理不能检测reactive对象
unref安全获取值处理可能为Ref的值等价于val = isRef(v) ? v.value : v

七、实战最佳实践

7.1 Ref与Reactive的黄金组合

const state = reactive({
  count: ref(0),      // 基本类型用ref包装
  user: {             // 对象直接嵌套
    name: 'Alice',
    age: ref(25)      // 混合使用
  }
})

7.2 组合式函数参数处理

// 同时接受ref和普通值
function useSmartAdd(target) {
  return computed(() => unref(target) + 10)
}

const num = ref(5)
console.log(useSmartAdd(num).value)  // 15
console.log(useSmartAdd(20).value)   // 30

7.3 类型安全进阶

interface User {
  name: string
  age: number
}

// Ref类型推断
const user = ref<User>({
  name: 'Bob',
  age: 30
})

// 自定义Ref类型
function useTimestampRef(): Ref<number> {
  return ref(Date.now())
}

八、常见陷阱破解

Q:为什么修改shallowRef的深层属性不触发更新?
A:shallowRef只监听.value的替换,需要强制更新时:

import { triggerRef } from 'vue'
shallowRef.value.deepProp = 'new'
triggerRef(shallowRef) // 手动触发

Q:toRefs解构后如何保持类型提示?

const state = reactive({ x: 0, y: 0 })
const { x, y } = toRefs(state) // 自动推断为Ref<number>

Q:unref在组合式函数中的典型应用?

// 参数智能处理
function usePosition(target) {
  const x = ref(unref(target.x))
  const y = ref(unref(target.y))
  // ...
}

九、生态整合

9.1 与Vue Router整合

import { useRoute } from 'vue-router'

const route = useRoute()
watch(() => route.params.id, (newId) => {
  // 处理路由变化
})

9.2 状态管理集成

// Pinia示例
import { useStore } from './store'

const store = useStore()
const doubleCount = computed(() => store.count * 2)

十、总结升华

Ref全家桶是Vue3响应式系统的瑞士军刀:

  • 核心三剑客:ref/shallowRef/customRef 构建响应式基础
  • 转换双雄:toRef/toRefs 打通响应式血脉
  • 工具搭档:isRef/unref 提升开发体验

掌握这些工具的组合使用,就像拥有了响应式编程的乐高积木,可以搭建出各种复杂的响应式系统。记住三个黄金原则:

  1. 按需选择:根据数据结构选择响应深度
  2. 类型安全:充分利用TS类型系统
  3. 组合优先:通过组合简单Ref构建复杂逻辑

(本文代码示例基于Vue3.4+,部分特性需注意浏览器兼容性)

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

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

相关文章

SpringCloud - Sentinel服务保护

前言 该博客为Sentinel学习笔记&#xff0c;主要目的是为了帮助后期快速复习使用 学习视频&#xff1a;7小快速通关SpringCloud 辅助文档&#xff1a;SpringCloud快速通关 源码地址&#xff1a;cloud-demo 一、简介 官网&#xff1a;https://sentinelguard.io/zh-cn/index.h…

单片机上SPI和IIC的区别

SPI&#xff08;Serial Peripheral Interface&#xff09;和IC&#xff08;Inter-Integrated Circuit&#xff09;是两种常用的嵌入式外设通信协议&#xff0c;它们各有优缺点&#xff0c;适用于不同的场景。以下是它们的详细对比&#xff1a; — 1. 基本概念 SPI&#xff0…

03-DevOps-安装并初始化Gitlab

Gitlab可以理解为是自己搭建的GitHub&#xff0c;也就是自己的代码仓库。 开启macvlan 在192.168.1.10服务器上&#xff0c;构建Macvlan网络&#xff0c;这种网络模式可以为每个容器独立分配ip。 docker network create -d macvlan \--subnet192.168.1.0/24 \--ip-range192.16…

RabbitMQ 从入门到精通:从工作模式到集群部署实战(五)

#作者&#xff1a;闫乾苓 系列前几篇&#xff1a; 《RabbitMQ 从入门到精通&#xff1a;从工作模式到集群部署实战&#xff08;一&#xff09;》&#xff1a;link 《RabbitMQ 从入门到精通&#xff1a;从工作模式到集群部署实战&#xff08;二&#xff09;》&#xff1a; lin…

DFS+回溯+剪枝(深度优先搜索)——搜索算法

DFS也就是深度优先搜索&#xff0c;比如二叉树的前&#xff0c;中&#xff0c;后序遍历都属于DFS。其本质是递归&#xff0c;要学好DFS首先需要掌握递归。接下来咱们就一起来学习DFS涉及的算法。 一、递归 1.什么是递归&#xff1f; 递归可以这样理解把它拆分出来&#xff0…

使用PyCharm创建项目以及如何注释代码

创建好项目后会出现如下图所示的画面&#xff0c;我们可以通过在项目文件夹上点击鼠标右键&#xff0c;选择“New”菜单下的“Python File”来创建一个 Python 文件&#xff0c;在给文件命名时建议使用英文字母和下划线的组合&#xff0c;创建好的 Python 文件会自动打开&#…

Spring MVC 拦截器(Interceptor)与过滤器(Filter)的区别?

1、两者概述 拦截器&#xff08;Interceptor&#xff09;&#xff1a; 只会拦截那些被 Controller 或 RestController 标注的类中的方法处理的请求&#xff0c;也就是那些由 Spring MVC 调度的请求。过滤器&#xff08;Filter&#xff09;&#xff1a; 会拦截所有类型的 HTTP …

【零基础学Mysql】常用函数讲解,提升数据操作效率的利器

以耳倾听世间繁华&#xff0c;以语表达心中所想 大家好,我是whisperrrr. 前言&#xff1a; 大家好&#xff0c;我是你们的朋友whisrrr。在日常工作中&#xff0c;MySQL作为一款广泛使用的开源关系型数据库&#xff0c;其强大的功能为我们提供了便捷的数据存储和管理手段。而在…

防火墙安全综合实验

防火墙安全综合实验 一、拓扑信息 二、需求及配置 实验步骤 需求一&#xff1a;根据下表&#xff0c;完成相关配置 设备接口VLAN接口类型SW2GE0/0/2VLAN 10AccessGE0/0/3VLAN 20AccessGE0/0/1VLAN List&#xff1a;10 20Trunk 1、创建vlan10和vlan20 2、将接口划分到对应…

RabbitMQ 消息顺序性保证

方式一&#xff1a;Consumer设置exclusive 注意条件 作用于basic.consume不支持quorum queue 当同时有A、B两个消费者调用basic.consume方法消费&#xff0c;并将exclusive设置为true时&#xff0c;第二个消费者会抛出异常&#xff1a; com.rabbitmq.client.AlreadyClosedEx…

DeepSeek R1 简单指南:架构、训练、本地部署和硬件要求

DeepSeek R1 简单指南&#xff1a;架构、训练、本地部署和硬件要求 DeepSeek 的 LLM 推理新方法 DeepSeek 推出了一种创新方法&#xff0c;通过强化学习 (RL) 来提高大型语言模型 (LLM) 的推理能力&#xff0c;其最新论文 DeepSeek-R1 对此进行了详细介绍。这项研究代表了我们…

1.攻防世界 unserialize3(wakeup()魔术方法、反序列化工作原理)

进入题目页面如下 直接开审 <?php // 定义一个名为 xctf 的类 class xctf {// 声明一个公共属性 $flag&#xff0c;初始值为字符串 111public $flag 111;// 定义一个魔术方法 __wakeup()// 当对象被反序列化时&#xff0c;__wakeup() 方法会自动调用public function __wa…

【R语言】卡方检验

一、定义 卡方检验是用来检验样本观测次数与理论或总体次数之间差异性的推断性统计方法&#xff0c;其原理是比较观测值与理论值之间的差异。两者之间的差异越小&#xff0c;检验的结果越不容易达到显著水平&#xff1b;反之&#xff0c;检验结果越可能达到显著水平。 二、用…

2025.2.9机器学习笔记:PINN文献阅读

2025.2.9周报 文献阅读题目信息摘要Abstract创新点网络架构实验结论缺点以及后续展望 文献阅读 题目信息 题目&#xff1a; GPT-PINN:Generative Pre-Trained Physics-Informed Neural Networks toward non-intrusive Meta-learning of parametric PDEs期刊&#xff1a; Fini…

JVM(Java 虚拟机)

Java语言的解释性和编译性&#xff08;通过JVM 的执行引擎&#xff09; Java 代码&#xff08;.java 文件&#xff09;要先使用 javac 编译器编译为 .class 文件&#xff08;字节码&#xff09;&#xff0c;紧接着再通过JVM 的执行引擎&#xff08;Execution Engine&#xff09…

利用二分法进行 SQL 盲注

什么是sql注入&#xff1f; SQL 注入&#xff08;SQL Injection&#xff09;是一种常见的 Web 安全漏洞&#xff0c;攻击者可以通过构造恶意 SQL 语句来访问数据库中的敏感信息。在某些情况下&#xff0c;服务器不会直接返回查询结果&#xff0c;而是通过布尔值&#xff08;Tr…

大模型数据集全面整理:444个数据集下载地址

本文针对Datasets for Large Language Models: A Comprehensive Survey 中的 444 个数据集&#xff08;涵盖8种语言类别和32个领域&#xff09;进行完整下载地址整理收集。 2024-02-28&#xff0c;由杨刘、曹家欢、刘崇宇、丁凯、金连文等作者编写&#xff0c;深入探讨了大型语…

Linux 创建进程 fork()、vfork() 与进程管理

Linux 创建进程 fork、vfork、进程管理 一、Linux的0号、1号、2号进程二、Linux的进程标识三、fork() 函数1、基本概念2、函数特点3、用法以及应用场景&#xff08;1&#xff09;父子进程执行不同的代码&#xff08;2&#xff09;进程执行另一个程序 4、工作原理 四、vfork() 函…

2025web寒假作业二

一、整体功能概述 该代码构建了一个简单的后台管理系统界面&#xff0c;主要包含左侧导航栏和右侧内容区域。左侧导航栏有 logo、管理员头像、导航菜单和安全退出按钮&#xff1b;右侧内容区域包括页头、用户信息管理内容&#xff08;含搜索框和用户数据表格&#xff09;以及页…

鸿蒙NEXT API使用指导之文件压缩和邮件创建

鸿蒙NEXT API 使用指导 一、前言二、邮件创建1、拉起垂类应用2、 UIAbilityContext.startAbilityByType 原型2.1、wantParam2.2、abilityStartCallback 与 callback 3、拉起邮箱类应用3.1、单纯拉起邮箱应用3.2、传入带附件的邮件 三、压缩文件1、认识 zlib2、压缩处理2.1、单文…