Vue3为什么推荐使用ref而不是reactive

news2025/1/9 1:37:48

为什么推荐使用ref而不是reactive

reactive本身具有很大局限性导致使用过程需要额外注意,如果忽视这些问题将对开发造成不小的麻烦;ref更像是vue2时代option apidata的替代,可以存放任何数据类型,而reactive声明的数据类型只能是对象;

先抛出结论,再详细说原因:非必要不用reactive! (官方文档也有对应的推荐)

官方原文:建议使用 ref() 作为声明响应式状态的主要 API。

最懂Vue的人都这么说了:推荐ref!!!

image.png

reactiveref 对比

reactiveref
❌只支持对象和数组(引用数据类型)✅支持基本数据类型+引用数据类型
✅在 <script><template> 中无差别使用❌在 <script><template> 使用方式不同(script中要.value)
❌重新分配一个新对象会丢失响应性✅重新分配一个新对象不会失去响应
能直接访问属性需要使用 .value 访问属性
❌将对象传入函数时,失去响应✅传入函数时,不会失去响应
❌解构时会丢失响应性,需使用toRefs❌解构对象时会丢失响应性,需使用toRefs
  • ref 用于将基本类型的数据(如字符串、数字,布尔值等)和引用数据类型(对象) 转换为响应式数据。使用 ref 定义的数据可以通过 .value 属性访问和修改。
  • reactive 用于将对象转换为响应式数据,包括复杂的嵌套对象和数组。使用 reactive 定义的数据可以直接访问和修改属性。

原因1:reactive有限的值类型

reactive只能声明引用数据类型(对象)
let  obj = reactive({
   name: '小明',
   age : 18
})
ref既能声明基本数据类型,也能声明对象和数组;

Vue 提供了一个 ref() 方法来允许我们创建可以使用任何值类型的响应式 ref

//对象
const state = ref({})
//数组
const state2 = ref([])

原因2:reactive使用不当会失去响应:

reactive一时爽,使用不恰当的时候失去响应泪两行,开开心心敲代码过程中,会感叹!!咦?怎么不行?为什么这么赋值失去响应了? 辣鸡reactive!!! 我要用 ref 👉👉yyds

1. 给reactive赋一整个普通对象/reactive对象

通常在页面数据回显时,需要将AJAX请求获取的对象直接赋值给响应式对象,如果操作不当就导致reactive声明的对象失去响应

  • 赋值一个普通对象

    let state = reactive({ count: 0 })
    //这个赋值将导致state失去响应
    state = {count: 1}
    
  • 赋值一个reactive对象

    如果给reactive的响应式对象赋值普通对象会失去响应,那么给它赋值一个reactive的响应式对象不就行了吗?下面试试看

<template>
  {{state}}
</template><stcirpt setup>
const state = reactive({ count: 0 })
 //nextTick异步方法中修改state的值
nextTick(() => {
  //并不会触发修改DOM  ,说明失去响应了
  state = reactive({ count: 11 });
});
</stcirpt>

nexTick中给state赋值一个reactive的响应式对象,但是DOM并没有更新!

解决方法:
  1. 不要直接整个对象替换,对象属性一个个赋值

    let state = reactive({ count: 0 })
    //state={count:1}
    state.conut = 1 
    
  2. 使用Object.assign

    let state = reactive({ count: 0 })
    // state =  {count:1}   state失去响应
    state = Object.assign(state , {count:1})
    
  3. 使用ref定义对象

    非必要不用reactive

    let state = ref({ count: 0 })
    state.value={count:1}
    
为什么同样是赋值对象ref不会失去响应而reactive会?

ref 定义的数据(包括对象)时,返回的对象是一个包装过的简单值,而不是原始值的引用;

就和对象深拷贝一样,是将对象属性值的赋值

reactive定义数据(必须是对象),reactive返回的对象是对原始对象的引用,而不是简单值的包装。

类似对象的浅拷贝,是保存对象的栈地址,无论值怎么变还是指向原来的对象的堆地址;

reactive就算赋值一个新的对象,reactive还是指向原来对象堆地址

2.将reactive对象的属性-赋值给变量(断开连接/深拷贝)

这种类似深拷贝不共享同一内存地址了,只是字面量的赋值;对该变量赋值也不会影响原来对象的属性值

let state = reactive({ count: 0 })
//赋值
// n 是一个局部变量,同 state.count
// 失去响应性连接
let n = state.count
// 不影响原始的 state
n++
console.log(state.count) //0

有人就说了,既然赋值对象的属性,那我赋值一整个对象不就是浅拷贝了吗?那不就是上面说的给响应式对象的字面量赋一整个普通对象/reactive对象这种情况吗?这种是会失去响应的

3.直接reactive对象解构时
  • 直接解构会失去响应
let state = reactive({ count: 0 })
//普通解构count 和 state.count 失去了响应性连接
let { count } = state 
count++ // state.count值依旧是0
解决方案:
  • 使用toRefs解构不会失去响应

    使用toRefs解构后的属性是ref的响应式数据

const state = reactive({ count: 0 })
//使用toRefs解构,后的属性为ref的响应式变量
let { count } = toRefs(state)
count.value++ // state.count值改变为1

建议: ref一把梭

当使用reactive时,如果不了解reactive失去响应的情况,那么使用reactive会造成很多困扰!

推荐使用ref总结原因如下:

  1. reactive有限的值类型:只能声明引用数据类型(对象/数组)

  2. reactive在一些情况下会失去响应,这个情况会导致数据回显失去响应(数据改了,dom没更新)

    给响应式对象的字面量赋一整个普通对象,将会导致reactive声明的响应式数据失去响应

    <template>
       {{state.a}}
       {{state.b}}
       {{state.c}}
    </template><script>
     let state = reactive({ a:1,b:2,c:3 })
     onMounted(()=>{
         //通AJAX请求获取的数据,回显到reactive,如果处理不好将导致变量失去响应,
        //回显失败,给响应式数据赋值一个普通对象
        state =  { a:11,b:22,c:333 }
       //回显成功,一个个属性赋值  
        state.a = 11
        state.b = 22
        state.c = 33 
     })
    </script>
    

    上面这个例子如果是使用ref进行声明,直接赋值即可,不需要将属性拆分一个个赋值

    使用ref替代reactive:

    <template>
       {{state.a}}
       {{state.b}}
       {{state.c}}
    </template><script>
     let state = ref({ a:1,b:2,c:3 })
     onMounted(()=>{
        //回显成功
        state.value =  { a:11,b:22,c:333 }
     })
    </script>
    
  3. ref适用范围更大,声明的数据类型.基本数据类型和引用数据类型都行

虽然使用ref声明的变量,在读取和修改时都需要加.value小尾巴,但是正因为是这个小尾巴,我们review代码的时候就很清楚知道这是一个ref声明的响应式数据;

ref的.value小尾巴好麻烦!

ref声明的响应式变量携带迷人的.value小尾巴,让我们一眼就能确定它是一个响应式变量!虽然使用ref声明的变量,在读取和修改时都需要加.value小尾巴,但是正因为是这个小尾巴,我们review代码的时候就很清楚知道这是一个ref声明的响应式数据;

可能有些人不喜欢这个迷人小尾巴,如果我能自动补全阁下又如何应对?

volar插件能自动补全.value (强烈推荐!!!)

本人推荐ref一把梭,但是ref又得到处.value ,那就交给插件来完成吧!!!

  • valor 自动补全.value (不是默认开启,需要手动开启)

  • 不会有人不知道Vue3需要不能使用vetur要用valor替代吧?不会不会吧? (必备volar插件)

volar设置自动填充value.gif 可以看到当输入ref声明的响应式变量时,volar插件自动填充.value 那还有啥烦恼呢? 方便!

本文会根据各位的提问和留言持续更新;

@ 别骂了_我真的不懂vue 说(总结挺好的,因此摘抄了):

reactive 重新赋值丢失响应是因为引用地址变了,被proxy代理的对象已经不是原来那个所以丢失响应了,其实ref也是一样的,当把.value那一层替换成另外一个有着.value的对象也会丢失响应 ref定义的属性等价于reactive({value:xxx})
另外说使用Object.assign为什么可以更新模板
Object.assign解释是这样的: 如果目标对象与源对象具有相同的键(属性名),则目标对象中的属性将被源对象中的属性覆盖,后面的源对象的属性将类似地覆盖前面的源对象的同名属性。
那个解决方法里不用重新赋值,直接Object.assign(state,{count:1})即可,所以只要proxy代理的引用地址没变,就会一直存在响应性

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

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

相关文章

医学影像SAM

医学影像SAM 1. 医学影像SAM1.1. MedSAM1.2. SAM-Adapter1.3. Medical-SAM-Adapter1.4. sam-med2d1.5. MS-SAM 下面整理了一些比较好的博客。 1. 医学影像SAM 由于sam在医学影像上表现不是特别好&#xff0c;在该类型数据集上就需要再训练。 1.1. MedSAM MedSAM&#xff1a…

【双塔模型DSSM】的原理与实现

文章目录 简介1 双塔模型的召回结构1.1 样本准备1.2 模型特征1.3 模型loss1.4 线上部署 2 双塔模型的粗排结构2.1 样本准备2.2 模型特征2.3 模型loss2.4 线上部署 参考文章 简介 DSSM 模型总的来说可以分成三层结构&#xff0c;分别是输入层、表示层和匹配层。双塔结构如下图所…

机器学习第十一课--K-Means聚类

一.聚类的概念 K-Means算法是最经典的聚类算法&#xff0c;几乎所有的聚类分析场景&#xff0c;你都可以使用K-Means&#xff0c;而且在营销场景上&#xff0c;它就是"King"&#xff0c;所以不管从事数据分析师甚至是AI工程师&#xff0c;不知道K-Means是”不可原谅…

虚拟机安装CentOS 7

一、CentOS7.4下载 官网下载地址&#xff1a;http://vault.centos.org/ 1、进入CentOS下载官网&#xff0c;找到CentOS7.4版本往下滑找到要下载的版本&#xff08;这里我用的是7.4哈~~&#xff09; 下载完成之后&#xff0c;由于“CentOS-7-x86_64-DVD-1708.torrent”只是一…

Python 找出最大数

"""在输入的三个数中找出最大知识点&#xff1a;1、条件嵌套语句if/else2.字符串分割函数split()3、列表元素索引4、数据类型转换举一反三&#xff1a;1、如何控制只能输入三个数&#xff0c;否则重新输入2、如何避免输入无效字母"""# 定义一个变…

Cron表达式_用于定时调度任务

一、Cron表达式简介 Cron表达式是一个用于设置计划任务的字符串&#xff0c;该字符串以5或6个空格分隔&#xff0c;分为6或7个域&#xff0c;每一个域代表任务在相应时间、日期或时间间隔执行的规则【Cron表达式最初是在类Unix操作中系统中使用的&#xff0c;但现在已经广泛应用…

三菱PLC位置式PID(梯形图源代码)

PID的算法和公式详细介绍,大家可以查看PID专栏,这里不再展开细述。这篇文章主要给出FX3GA系列位置式PID的梯形图源代码,方便大家学习使用。 位置式PID三菱ST代码 三菱FX3U PLC 位置式PID算法(ST语言)_三菱pid梯形图源代码_RXXW_Dor的博客-CSDN博客三菱PLC自带的PID不必多说…

uniapp:如何修改组件默认样式

日历组件默认样式如下图&#xff0c;但是我不想要右上角的红点&#xff0c;并且日期下面的数字要加红色背景&#xff0c;变成圆形&#xff0c;还是先用元素检查找到元素的类名&#xff0c;然后通过/deep/来覆盖样式&#xff0c;需要注意的是&#xff0c;lang要scss或者less&…

硬件基本功--MOS管

一、上下拉电阻Rgs的作用 Rgs&#xff1a;经验值&#xff0c;一般取10K左右。 1. 上电时给MOS管的栅极一个确定的电平&#xff0c;防止上电时GPIO为高阻态时&#xff0c;MOS管的栅极电平不确定&#xff0c;从而受到干扰。 2. 断电时&#xff0c;如果MOS管是导通的状态&#xff…

北京智和信通亮相2023IT运维大会,共话数智浪潮下自动化运维新生态

2023年9月21日&#xff0c;由IT运维网、《网络安全和信息化》杂志社联合主办的“2023&#xff08;第十四届&#xff09;IT运维大会”在北京成功举办。大会以“以数为基 智引未来”为主题&#xff0c;北京智和信通技术有限公司&#xff08;下文简称&#xff1a;北京智和信通&…

火山引擎边缘云:数智化项目管理助力下的业务增长引擎

近日&#xff0c;“QCon全球软件开发大会2023北京站”、“第十二届中国PMO大会”、“2023第二届中国PMO&PM大会”相继召开&#xff0c;火山引擎边缘云项目管理团队受邀参加&#xff0c;并就项目管理相关主题开展分享。 会上&#xff0c;火山引擎边缘云项目管理负责人申建表…

TS编译器选项​——指定编译后文件所在目录

compilerOptions是TS的编译器选项&#xff0c;主要在tsconfig.json文件中用于对ts编译为js文件时进行配置 "compilerOptions" : { 配置项 } 在tsconfig.json中编写如下代码&#xff1a; {// compilerOptions 编译器选项"compilerOptions": {// outDir 用于…

QT程序打包图片无法正常显示

QT程序打包图片无法正常显示 环境&#xff1a; QT4.8.2VS2017opencv3.416 问题&#xff1a; 本机测试正常&#xff0c;图片可正常显示功能也可正常进行&#xff0c;但打包发送给没有环境数据的电脑上进行测试就会出现图片无法显示的问题。 原因&#xff1a; 并没有找到理论支撑…

投资理财知识分享:100个金融知识专业术语

大家好&#xff0c;我是财富智星&#xff0c;今天跟大家分享一下投资理财知识方面100个金融知识专业术语&#xff0c;希望能帮助大家了解更多金融知识。 1. 股票&#xff1a;代表对一家公司所有权的证券。 2. 债券&#xff1a;公司或政府发行的借款证券。 3. 投资组合&#xff…

AWS SAA 学习过程记录

共通 一些信息已经更新了&#xff0c;但参考题的答案还是旧的。 比如&#xff1a; S3的最大读写性能已经提高到 3,500 PUT/COPY/POST/DELETE or 5,500 GET/HEAD requests per second 并且不再要求使用random prefix Storage Amazon S3 为了提高读取的performance: For exam…

MySQL 笔试——多表连接查询

一、&#xff08;左、右和全&#xff09;连接概念 内连接&#xff1a; 假设A和B表进行连接&#xff0c;使用内连接的话&#xff0c;凡是A表和B表能够匹配上的记录查询出来。A和B两张表没有主付之分&#xff0c;两张表是平等的。 关键字&#xff1a;inner join on 语句&#xf…

2023-9-25 JZ6 从头到尾打印链表

题目链接&#xff1a;从头到尾打印链表 import java.util.*; /** * public class ListNode { * int val; * ListNode next null; * * ListNode(int val) { * this.val val; * } * } * */ import java.util.ArrayList; public c…

【MySql】2- 基础篇(下)

文章目录 1. MySQL锁1. 1 全局锁1. 2 表级锁1. 3 行锁1. 3 .1 两阶段锁1. 3 .2 死锁和死锁检测 2. 事务是否是隔离的?2.1 快照在MVCC中如何工作 1. MySQL锁 数据库锁设计的初衷是处理并发问题。作为多用户共享的资源&#xff0c;当出现并发访问的时候&#xff0c;数据库需要合…

Android修行手册 - Activity 在 Java 和 Kotlin 中怎么写构造参数

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…

无线通信——Mesh自组网的由来

阴差阳错找到了一个工作&#xff0c;是做无线通信的&#xff0c;因为无线设备采用Mesh&#xff0c;还没怎么接触过&#xff0c;网上搜索下发现Mesh的使用场景不多&#xff0c;大部分都是用在家里路由器上面。所以写了片关于Mesh网的文档。Mesh网可应用在无网络区域的地方&#…