Vue3为什么推荐使用ref而不是reactive
yuyutoo 2025-05-02 14:26 6 浏览 0 评论
为什么推荐使用ref而不是reactive
reactive本身具有很大局限性导致使用过程需要额外注意,如果忽视这些问题将对开发造成不小的麻烦;ref更像是vue2时代option api的data的替代,可以存放任何数据类型,而reactive声明的数据类型只能是对象;
先抛出结论,再详细说原因:非必要不用reactive! (官方文档也有对应的推荐)
官方原文:建议使用 ref() 作为声明响应式状态的主要 API。
最懂Vue的人都这么说了:推荐ref!!!!!!
reactive和ref对比
reactive | ref |
只支持对象和数组(引用数据类型) | 支持基本数据类型+引用数据类型 |
在 <script> 和 <template> 中无差别使用 | 在 <script> 和 <template> 使用方式不同(script中要.value) |
重新分配一个新对象会丢失响应性 | 重新分配一个新对象不会失去响应 |
能直接访问属性 | 需要使用 .value 访问属性 |
将对象传入函数时,失去响应 | 传入函数时,不会失去响应 |
解构时会丢失响应性,需使用toRefs | 解构对象时会丢失响应性,需使用toRefs |
原因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并没有更新!
解决方法:
- 不要直接整个对象替换,对象属性一个个赋值
let state = reactive({ count: 0 })
//state={count:1}
state.conut = 1
- 使用Object.assign
let state = reactive({ count: 0 })
// state = {count:1} state失去响应
state = Object.assign(state , {count:1})
- 使用ref定义对象
非必要不用reactive
let state = ref({ count: 0 })
state.value={count:1}
为什么同样是赋值对象ref不会失去响应而reactive会?
ref 定义的数据(包括对象)时,返回的对象是一个包装过的简单值,而不是原始值的引用;
就和对象深拷贝一样,是将对象属性值的赋值
reactive定义数据(必须是对象),reactive返回的对象是对原始对象的引用,而不是简单值的包装。
类似对象的浅拷贝,是保存对象的栈地址,无论值怎么变还是指向原来的对象的堆地址;
reactive就算赋值一个新的对象,reactive还是指向原来对象堆地址
.将reactive对象的属性-赋值给变量(断开连接/深拷贝)
这种类似深拷贝不共享同一内存地址了,只是字面量的赋值;对该变量赋值也不会影响原来对象的属性值
let state = reactive({ count: 0 })
//赋值
// n 是一个局部变量,同 state.count
// 失去响应性连接
let n = state.count
// 不影响原始的 state
n++
console.log(state.count) //0
有人就说了,既然赋值对象的属性,那我赋值一整个对象不就是浅拷贝了吗?那不就是上面说的给响应式对象的字面量赋一整个普通对象/reactive对象这种情况吗?这种是会失去响应的
.直接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总结原因如下:
- reactive有限的值类型:只能声明引用数据类型(对象/数组)
- 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>
- ref适用范围更大,声明的数据类型.基本数据类型和引用数据类型都行
虽然使用ref声明的变量,在读取和修改时都需要加.value小尾巴,但是正因为是这个小尾巴,我们review代码的时候就很清楚知道这是一个ref声明的响应式数据;
ref的.value小尾巴好麻烦!
ref声明的响应式变量携带迷人的.value小尾巴,让我们一眼就能确定它是一个响应式变量!虽然使用ref声明的变量,在读取和修改时都需要加.value小尾巴,但是正因为是这个小尾巴,我们review代码的时候就很清楚知道这是一个ref声明的响应式数据;
可能有些人不喜欢这个迷人小尾巴,如果我能自动补全阁下又如何应对?
volar插件能自动补全.value(强烈推荐!!!!!!!)
本人推荐ref一把梭,但是ref又得到处.value ,那就交给插件来完成吧!!!
- valor 自动补全.value (不是默认开启,需要手动开启)
- 不会有人不知道Vue3需要不能使用vetur要用valor替代吧?不会不会吧? (必备volar插件)
可以看到当输入ref声明的响应式变量时,volar插件自动填充.value 那还有啥烦恼呢? 方便!
本文会根据各位的提问和留言持续更新;
@ 别骂了_我真的不懂vue 说(总结挺好的,因此摘抄了):
reactive 重新赋值丢失响应是因为引用地址变了,被proxy代理的对象已经不是原来那个所以丢失响应了,其实ref也是一样的,当把.value那一层替换成另外一个有着.value的对象也会丢失响应 ref定义的属性等价于reactive({value:xxx})
另外说使用Object.assign为什么可以更新模板
Object.assign解释是这样的: 如果目标对象与源对象具有相同的键(属性名),则目标对象中的属性将被源对象中的属性覆盖,后面的源对象的属性将类似地覆盖前面的源对象的同名属性。
那个解决方法里不用重新赋值,直接Object.assign(state,{count:1})即可,所以只要proxy代理的引用地址没变,就会一直存在响应性
原文链接:
https://juejin.cn/post/7270519061208154112
相关推荐
- 对volatile,synchronized,AQS的加锁解锁原理的一些理解
-
一、为什么要加锁,要实现同步多线程编程中,有可能会出现多个线程同时访问同一个共享、可变资源的情况,这个资源我们称之其为临界资源;这种资源可能是:对象、变量、文件等。...
- 注意,不能错过的CAS+volatile实现同步代码块
-
前言:最近看到有人说可以使用CAS+volatile实现同步代码块。心想,确实是可以实现的呀!因为AbstractQueuedSynchronizer(简称AQS)内部就是通过CAS+...
- 面试并发volatile关键字时,我们应该具备哪些谈资?
-
提前发现更多精彩内容,请访问https://dayarch.top/提前发现更多精彩内容,请访问https://dayarch.top/提前发现更多精彩内容,请访问https://dayarch...
- 无锁同步-JAVA之Volatile、Atomic和CAS
-
1、概要本文是无锁同步系列文章的第二篇,主要探讨JAVA中的原子操作,以及如何进行无锁同步。关于JAVA中的原子操作,我们很容易想到的是Volatile变量、java.util.concurrent....
- C/C++面试题(二):std::atomic与volatile
-
volatile是C/C++中的一个关键字,用于告知编译器某个变量的值可能会在程序的控制之外被意外修改(例如被硬件、中断服务程序、多线程环境或其他外部代理)。为了防止编译器对代码进行某些可能破坏...
- VOCs(Volatile Organic Compounds)挥发性有机化合物及测试方法
-
经常看到一些三防漆、涂料、油漆类产品的介绍中提到VOC、VOCs等概念,那么什么是VOC、VOCs和TVOC,VOCs主要包括哪些物质?VOCs的来源有哪些?VOCs的危害及国家标准是什么?一、V...
- 对volatile 及happen—before的理解
-
happen—before规则介绍Java...
- 这一篇我们来了解Synchronized、Volatile、Final关键字
-
题外话:蓝银王觉醒了!!--来自于一个斗罗大陆动漫爱好者(鹅,打钱!)湿兄这两天回家了,办了点大事,回来的时候我弟弟还舍不得我,哭着不愿意让我回京(我弟还是小学),我也心里很不舍,但是还是要回京奋斗...
- 关于 Java 关键字 volatile 的总结
-
1什么是volatilevolatile是Java的一个关键字,它提供了一种轻量级的同步机制。相比于重量级锁synchronized,volatile更为轻量级,因为它不会引起线程上下文...
- 大白话聊聊Java并发面试问题之volatile到底是什么?
-
用最简单的大白话,加上多张图给大家说一下,volatile到底是什么?...
- 为什么要有volatile关键字(volatile 关键字为什么不能保证原子性)
-
在嵌入式编程和多线程编程中,我们常会见到volatile关键字声明的变量。下面说一下volatile关键字的作用:1.保持变量内存可见简而言之就是用volatile声明的变量会告诉编译器和处理器,这个...
- Java的volatile到底怎么理解?(java volatitle)
-
我们都知道,在Java中有很多的关键字,比如synchronize比如volatile,这些都是一些比较关键的,还有final,今天我们就来聊一下这个volatile因为这个vo...
- Java多线程编程中的volatile关键字:解密神秘的共享内存
-
Java多线程编程中的volatile关键字:解密神秘的共享内存在Java多线程编程的世界里,volatile关键字就像一位低调却至关重要的守护者。它默默无闻地站岗放哨,确保多个线程之间能够正确地共享...
- 你了解volatile关键字的作用吗?(关键字volatile有什么含意?并举出三个不同的例子?)
-
【死记硬背】volatile关键字主要用于保持内存的变量可见性和禁止重排序。变量可见性:当一个线程改变了变量的值,那么新的值对于其他线程也是可以立即获取到的。禁止重排序:...
- 谈谈你对volatile 关键字作用和原理的理解
-
一位6年工作经验的小伙伴,在某里二面的时候被问到“volatile”关键字。然后,就没有然后了…同样,还有一位4年的小伙伴,去某团面试也被问到“volatile关键字“。然后,也没有然后了…...
你 发表评论:
欢迎- 一周热门
-
-
前端面试:iframe 的优缺点? iframe有那些缺点
-
带斜线的表头制作好了,如何填充内容?这几种方法你更喜欢哪个?
-
漫学笔记之PHP.ini常用的配置信息
-
其实模版网站在开发工作中很重要,推荐几个参考站给大家
-
推荐7个模板代码和其他游戏源码下载的网址
-
[干货] JAVA - JVM - 2 内存两分 [干货]+java+-+jvm+-+2+内存两分吗
-
正在学习使用python搭建自动化测试框架?这个系统包你可能会用到
-
织梦(Dedecms)建站教程 织梦建站详细步骤
-
【开源分享】2024PHP在线客服系统源码(搭建教程+终身使用)
-
2024PHP在线客服系统源码+完全开源 带详细搭建教程
-
- 最近发表
-
- 对volatile,synchronized,AQS的加锁解锁原理的一些理解
- 注意,不能错过的CAS+volatile实现同步代码块
- 面试并发volatile关键字时,我们应该具备哪些谈资?
- 无锁同步-JAVA之Volatile、Atomic和CAS
- C/C++面试题(二):std::atomic与volatile
- VOCs(Volatile Organic Compounds)挥发性有机化合物及测试方法
- 对volatile 及happen—before的理解
- 这一篇我们来了解Synchronized、Volatile、Final关键字
- 关于 Java 关键字 volatile 的总结
- 大白话聊聊Java并发面试问题之volatile到底是什么?
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)