全面掌握Vue 3响应式:ref自动解包、reactive对象替换及响应式丢失问题

Vue 3的响应式系统是其最核心的特性之一,主要通过refreactive这两个API来实现。本文将详细介绍这两个API的使用方法、区别以及最佳实践。

1. ref()的基本使用

ref()用于创建一个响应式的数据引用。它可以包装任何类型的值,包括基本类型和对象类型。

1.1 基本类型示例

import { ref } from 'vue'// 创建一个ref
const count = ref(0)// 访问值
console.log(count.value) // 0// 修改值
count.value++
console.log(count.value) // 1// 在模板中使用(不需要.value)
<template><div>{{ count }}</div>
</template>

1.2 对象类型示例

import { ref } from 'vue'const user = ref({name: 'Alice',age: 25
})// 访问和修改对象属性
console.log(user.value.name) // 'Alice'
user.value.age = 26// 替换整个对象
user.value = {name: 'Bob',age: 30
}

2. reactive()的基本使用

reactive()用于创建一个响应式对象,但只能用于对象类型(包括数组和Map、Set等集合类型)。

reactive() 返回的是一个原始对象的 Proxy,它和原始对象是不相等的:

const raw = {}
const proxy = reactive(raw)// 代理对象和原始对象不是全等的
console.log(proxy === raw) // false

2.1 基本示例

import { reactive } from 'vue'const state = reactive({user: {name: 'Alice',age: 25},posts: []
})// 直接访问和修改属性(不需要.value)
console.log(state.user.name) // 'Alice'
state.user.age = 26
state.posts.push({ id: 1, title: 'Hello Vue 3' })

2.2 数组示例

const list = reactive([1, 2, 3])// 数组方法都会触发响应式更新
list.push(4)
list.pop()
list[0] = 10

3. ref vs reactive的主要区别

  1. 使用方式

    • ref:需要通过.value访问和修改值(模板中例外)
    • reactive:直接访问和修改属性
  2. 适用类型

    • ref:可以包装任何类型
    • reactive:只能用于对象类型
    • ref 返回一个由 RefImpl 类构造出来的对象,而 reactive 返回一个原始对象的响应式代理 Proxy
  3. 嵌套转换

// ref的嵌套对象转换
const user = ref({name: 'Alice',info: { age: 25 }
})
// 结构:{ value: Proxy({ name: 'Alice', info: Proxy({ age: 25 }) }) }// reactive的嵌套对象转换
const state = reactive({user: {name: 'Alice',info: { age: 25 }}
})
// 结构:Proxy({ user: { name: 'Alice', info: Proxy({ age: 25 }) } })

4. 注意事项

  1. 响应式丢失情况
import { reactive, toRefs } from 'vue';
const state = reactive({ count: 0 })// ❌ 错误用法:解构后失去响应性
const { count } = state// ✅ 正确用法:使用计算属性
const count = computed(() => state.count)// ✅ 正确用法:使用toRefs
const { count } = toRefs(state); // 此时 count 仍然为响应式
  1. ref的自动解包
const count = ref(0)
const state = reactive({count // 在reactive对象中会自动解包
})console.log(state.count) // 直接访问值,不需要.value
  1. 不能直接替换reactive对象
let state = reactive({ count: 0 })// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({ count: 1 }) // 这将导致错误// ✅ 正确用法:修改属性值
state.count = 1//✅ 正确用法:使用 Object.assign 合并对象
Object.assign(state, { count: 1, otherProp: 'value' })//✅ 正确用法:如果存在替换整个对象的需求,可以考虑使用 ref 代替 reactive:
const state = ref({ count: 0 })
state.value = { count: 1 }  // 合法操作
  1. 在模板中解包
//在模板渲染上下文中,只有顶级的 ref 属性才会被解包。
//在下面的例子中,count 和 object 是顶级属性,但 object.id 不是:
const count = ref(0)
const object = { id: ref(1) }<template>
{{ count + 1 }}
<!-- 但下面这个不会:-->
{{ object.id + 1 }}
</template>
//渲染的结果将是 [object Object]1,因为在计算表达式时 object.id 没有被解包,仍然是一个 ref 对象。为了解决这个问题,我们可以将 id 解构为一个顶级属性:
<template><!-- 在模板中自动解包 --><div>{{ count }}</div><!-- 在v-bind中也会自动解包 --><input :value="count"><!-- 但在事件处理器中需要.value --><button @click="count.value++">增加</button>
</template>

5. 总结

1. 核心特性对比

特性refreactive
数据类型任何类型仅对象类型
访问方式.value(模板中自动解包)直接访问
实现方式RefImpl类Proxy
解构行为保持响应性失去响应性
对象处理内部使用reactive直接代理

2. 最佳实践要点

  1. 类型选择

    • 基本类型使用ref()
    • 复杂对象使用reactive()
    • 官方建议使用 ref() 作为声明响应式状态的主要 API
  2. 避免常见陷阱

    • 不要解构reactive对象
    • 不要直接替换reactive对象
    • 注意在事件处理器中使用ref需要.value
  3. 性能优化

    • 合理使用shallowRefshallowReactive
    • 避免不必要的深层响应式转换
    • 大型数据集合考虑使用shallowRef

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

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

相关文章

【科普】 AI大模型应用架构图大全

AI大模型应用架构图大全 AI大模型技术全景视图&#xff1a; AI大模型通用技术架构图 AI大模型通用技术架构图 AI大模型通用技术架构图 RAG知识库业务架构图 AI农业大模型技术架构图 AI导购大模型技术架构图 AI导购大模型技术架构图 AI大模型合规风控管理架构图 AI大模型合规管…

Educational Codeforces Round 180 (Rated for Div. 2) A-D题解

A. Race 题意 在一个数轴上&#xff0c;奖品可能出现在 x x x 点或 y y y 点&#xff0c;Alice 现在在 a a a 点&#xff0c;请问Bob是否存在一个点 b b b&#xff0c;使得无论奖品出现在 x x x 点还是 y y y 点&#xff0c;Bob都能比Alice先拿到&#xff08; ∣ b −…

IPv6配置

IPv6的基本配置 构建如下图所示的实训拓扑&#xff0c;按如下要求完成实训内容&#xff1a; &#xff08;1&#xff09;启用路由器的IPv6功能&#xff1b; &#xff08;2&#xff09;配置路由器接口的IPv6地址&#xff1b; &#xff08;3&#xff09;测试两台路由器的连通性…

flutter项目环境升级二:从Flutter2.10.5升级到3.29.3

系统:windows Android Studio:Android Studio Meerkat Feature Drop | 2024.3.2 Patch 1 Flutter SDK: Flutter3.29.3 JDK: java 17 详细的AGP / Gradle / Kotlin / JDK版本兼容关系可以百度或者到官方文档查询,其他博主给的很详细。确认好想要的版本兼容 这位大哥有对照表…

【网站内容安全检测】之1:获取网站所有链接sitemap数据

不多BB&#xff0c;直接上代码&#xff1a; main.go package mainimport ("bufio""crypto/tls""fmt""io""net/http""net/url""os""strings""sync""time"_ "net/ht…

从零构建vue3项目(二)

Vue3项目增强配置&#xff1a;Axios封装、鉴权与代码扫描 1. Axios二次封装与拦截器配置 安装Axios npm install axios创建Axios实例 src/utils/request.js import axios from axios import { useUserStore } from /stores/user import router from /router// 创建axios实例…

哪家香港站群服务器比较好用?

面对鱼龙混杂的服务商市场&#xff0c;哪家的香港站群服务器真正稳定&#xff1f;毕竟搞站群最怕的就是服务器抽风&#xff0c;轻则掉排名&#xff0c;重则客户跑光光。今天咱就重点聊聊哪家香港站群服务器比较好用&#xff1f; 一般来说&#xff0c;在选择香港站群服务器提供…

Python的科学计算库NumPy(二)

5. 索引和切片 5.1 一维数组的索引和切片 import numpy as np# 一维数组索引和切片&#xff0c;跟python中的集合同样使用 bin_list[1,2,3,4,5,6] bin_arraynp.array(bin_list) print(bin_array[3]) print(bin_array[1:4]) print(bin_array[-2:-1])5.2 多维数组的索引 # 多维…

STM32和C++ 实现配置文件导入、导出功能

一.配置文件导出功能 // 导出流程 // 1. 客户端 → 设备:导出配置请求,例如:GetFlashData[d6fe30323454]:{ini} ,其中[]里面是设备序列号 // 2. 设备 → 客户端:配置文件元数据(总大小、块数量) // 3. 设备 → 客户端:发送块1(包含块序号和大小) // 4. 设备 → 客户端:…

HTTP 请求基础知识

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言HTTP 请求方法GETPOSTPUTDELETE其他方法 HTTP 请求结构常用请求头实际应用示例响应状态码 前言 HTTP (Hypertext Transfer Protocol) 是互联网上应用最广泛的协…

Django ORM 1. 创建模型(Model)

1. ORM介绍 什么是ORM&#xff1f; ORM&#xff0c;全称 Object-Relational Mapping&#xff08;对象关系映射&#xff09;&#xff0c;一种通过对象操作数据库的技术。 它的核心思想是&#xff1a;我们不直接写 SQL&#xff0c;而是用 Python 对象&#xff08;类/实例&…

【C/C++】C++ 编程规范:101条规则准则与最佳实践

C 编程规范&#xff1a;101条规则准则与最佳实践 引言 C 是一门强大而复杂的语言&#xff0c;能高效控制硬件&#xff0c;也能写出优雅抽象。然而&#xff0c;正因其复杂性&#xff0c;项目中若缺乏统一规范&#xff0c;极易陷入混乱、难维护、易出错的泥潭。 本文总结了 10…

柔性屏激光修屏禁区突破:新启航如何实现曲面 OLED 面板的无损修复?

一、引言 柔性 OLED 面板凭借其轻薄、可弯曲等特性&#xff0c;在智能终端、可穿戴设备等领域广泛应用。然而&#xff0c;生产过程中面板易出现缺陷&#xff0c;传统修复方法难以满足曲面 OLED 面板的无损修复需求。新启航半导体有限公司在激光修屏技术上取得突破&#xff0c;…

UI前端与数字孪生结合案例分享:智慧零售的可视化解决方案

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩! 一、引言&#xff1a;智慧零售的可视化变革 在数字化浪潮下&#xff0c;零售行业正从 “人货场…

Docker 入门教程(四):容器命令

文章目录 &#x1f433; Docker 入门教程&#xff08;四&#xff09;&#xff1a;容器命令创建并运行容器&#xff1a;docker run查看容器列表&#xff1a;docker ps停止、启动、重启容器删除容器&#xff1a;docker rm进入容器&#xff1a;exec 和 attach查看容器日志&#xf…

2025.06.27【技术观察L0】AlphaGenome:DeepMind推出的全新AI基因组解读平台

AlphaGenome&#xff1a;DeepMind推出的全新AI基因组解读平台详解 2025年6月&#xff0c;Google DeepMind团队正式发布了AlphaGenome——一款面向基因组功能解读和变异效应预测的全新人工智能模型。AlphaGenome的出现&#xff0c;标志着AI在基因组学领域迈出了重要一步&#x…

[ARM-2D 专题]7. OOP实现之继承,宏implement_ex的实现和解析

implement_ex宏是 Arm-2D 库中用于面向对象编程&#xff08;OOP&#xff09;支持的核心宏定义。 implement_ex 宏的定义和作用 implement_ex 宏在 Library/Include/arm_2d_utils.h 中定义&#xff0c;用于在 C 语言中实现类似继承的功能&#xff1a; /*!* \note do NOT use t…

默认构造函数

1、构造函数 一、什么是构造函数 c中有一种特殊的成员函数&#xff0c;他的名字和类名相同&#xff0c;没有返回值&#xff0c;而在创建对象时会自动执行&#xff0c;类中的数据成员的初始化往往通过构造函数来实现。完成类中数据成员的初始化&#xff0c;同时也是类中的成员…

带标签的 Docker 镜像打包为 tar 文件

现在还有人用docker吗 要将带标签的 Docker 镜像打包为 tar 文件&#xff0c;请使用 docker save 命令。以下是详细操作指南&#xff1a; 一、单镜像打包&#xff08;推荐方式&#xff09; # 基础格式 docker save -o [输出文件名].tar [镜像名]:[标签]# 示例&#xff1a;将…

基于GPS-RTK的履带吊车跑偏检测技术方案

基于GPS-RTK的履带吊车跑偏检测技术方案 1. 引言 1.1 项目背景 履带吊车作为重型工程机械&#xff0c;其行驶稳定性直接关系到作业安全和设备寿命。跑偏现象会导致履带异常磨损、转向系统过载&#xff0c;严重时可能引发侧翻事故。传统检测方法&#xff08;如激光测距或人工观…