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

这篇具有很好参考价值的文章主要介绍了Vue3为什么推荐使用ref而不是reactive。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

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

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

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

Vue3为什么推荐使用ref而不是reactive,vue3,vue.js,javascript,前端

reactive和 ref 对比

reactive ref
❌只支持对象和数组(引用数据类型) ✅支持基本数据类型+引用数据类型
✅在 <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插件)

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

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

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

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

到了这里,关于Vue3为什么推荐使用ref而不是reactive的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • MySQL为什么不推荐使用in

    有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准 https://blog.zysicyj.top 首发博客地址 系列文章地址 当使用IN语句时,MySQL可能会遇到以下问题: 索引问题:MySQL使用索引来加速查询,但在使用IN语句时,MySQL可能无法有效地使用索引。这是因为

    2024年02月09日
    浏览(14)
  • 为什么不推荐使用Lombok?@Data不香吗?

    为什么不推荐使用Lombok?@Data不香吗?

    目录 一、前言 二、源码跟踪 三、总结 之前写项目遇到的一个Bug,下面是模拟代码。 新建一个springboot的项目,Person一个实体类,定义一个方法传一个JSON数据 springboot启动之后postman发送一次请求。 请求路径:http://localhost:8080/user JSON数据: 后台输出结果 我们会发现,aName字段

    2024年02月09日
    浏览(12)
  • 为什么js中不推荐使用eval函数

    \\\'eval\\\'函数是javascript中的一个内置函数,它的主要作用是将传入的字符串作为代码来执行。换句话说,\\\'eval\\\'可以将动态生成的字符串当作javascript代码来执行,并返回执行结果。 我的理解就是它可以执行传入的代码,并返回执行结果。 \\\'eval\\\'可以执行任何传入的字符串,所以意味

    2024年02月08日
    浏览(12)
  • 【Elasticsearch专栏 02】深入探索:Elasticsearch为什么使用倒排索引而不是正排索引

    Elasticsearch选择使用倒排索引而不是正排索引,主要是基于倒排索引在处理全文搜索和大规模数据集时的优势。下面将详细解释为什么Elasticsearch更倾向于使用倒排索引,并提供一些简化的代码片段来说明这两种索引结构的基本差异。 正排索引是一种将文档映射到其包含的单词

    2024年02月22日
    浏览(15)
  • 为什么很多企业依然再用jdk8而不是使用最新版本jdk17?

    为什么很多企业依然再用jdk8而不是使用最新版本jdk17?

    兼容性问题:JDK 8 是一个经过长期使用和测试的稳定版本,与许多企业应用程序和库已经兼容,而升级到新版本可能会导致兼容性问题。如果企业应用程序依赖于不再支持的 API 或过时的库,则升级到 JDK 17 可能需要进行重大更改。 安全问题:JDK 8 仍然受到支持,包括安全更

    2024年02月12日
    浏览(13)
  • 【Spring】浅谈spring为什么推荐使用构造器注入

    因本人实力有限,该文章主要内容(在文章基础上加了点点东西)均来自: 原文链接:https://www.cnblogs.com/joemsu/p/7688307.html 作者:joemsu ​ Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反转)和AOP,平时使用最多的就是其中的IOC,我们通过

    2024年02月13日
    浏览(12)
  • 【密码学】为什么不推荐在对称加密中使用CBC工作模式

    这篇文章是我在公司内部分享中一部分内容的详细版本,如标题所言,我会通过文字、代码示例、带你完整的搞懂为什么我们不建议你使用cbc加密模式,用了会导致什么安全问题,即使一定要用需要注意哪些方面的内容。 注:本文仅从安全角度出发,未考虑性能与兼容性等因

    2024年02月06日
    浏览(49)
  • Vue3.0里为什么要用 Proxy API 替代 defineProperty API ?

    Vue3.0里为什么要用 Proxy API 替代 defineProperty API ?

    定义: Object.defineProperty()  方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象 为什么能实现响应式 通过 defineProperty  两个属性, get 及 set get 属性的 getter 函数,当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 th

    2024年03月09日
    浏览(14)
  • 为什么Spring和IDEA不推荐使用@Autowired注解,有哪些替代方案?

    为什么Spring和IDEA不推荐使用@Autowired注解,有哪些替代方案?

    在使用Spring框架和JetBrains IDEA集成开发环境(IDE)进行Java开发时,你可能经常会遇到@Autowired注解。@Autowired是Spring框架中用于实现依赖注入的核心注解之一。然而,近年来,Spring和IDEA都不再推荐使用@Autowired注解,并提出了更好的替代方案。本文将详细分析为什么Spring和IDEA不

    2024年02月07日
    浏览(15)
  • 为什么聊天机器人界面不是未来

    为什么聊天机器人界面不是未来

    ​ 比如: 0 按时上下班,用固定时间长度获取价值 1 创业,用非线性时间,获取真实价值 0-1 之间有无限多种状态 shadow ChatBot目前的交互界面有非常多值得被改进的体验机会。最近看到一篇非常有启发性的文章,分享给大家。 核心观点来自于文章: https://wattenberger.com/though

    2024年02月03日
    浏览(12)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包