百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

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

yuyutoo 2025-05-02 14:26 26 浏览 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

  • 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并没有更新!

    解决方法:

    • 不要直接整个对象替换,对象属性一个个赋值
    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总结原因如下:

    1. reactive有限的值类型:只能声明引用数据类型(对象/数组)
    2. reactive在一些情况下会失去响应,这个情况会导致数据回显失去响应(数据改了,dom没更新)
    3. 给响应式对象的字面量赋一整个普通对象,将会导致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>
    1. 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


    相关推荐

    《保卫萝卜2》安卓版大更新 壕礼助阵世界杯

    《保卫萝卜2:极地冒险》本周不仅迎来了安卓版本的重大更新,同时将于7月4日本周五,带来“保卫萝卜2”安卓版本世界杯主题活动的火热开启,游戏更新与活动两不误。一定有玩家会问,激萌塔防到底进行了哪些更新?...

    儿童手工折纸:胡萝卜,和孩子一起边玩边学carrot

    1、准备两张正方形纸,一橙一绿,对折出折痕。2、橙色沿其中一条对角线如图折两三角形。3、把上面三角折平,如图。4、绿色纸折成三角形。5、再折成更小的三角形。6、再折三分之一如图。7、打开折纸,压平中间...

    《饥荒》食物代码有哪些(饥荒最新版代码总汇食物篇)

    饥荒游戏中,玩家们需要获取各种素材与食物,进行生存。玩家们在游戏中,进入游戏后按“~”键调出控制台使用代码,可以直接获得素材。比如胡萝卜的代码是carrot,玉米的代码是corn,南瓜的代码是pump...

    Skyscanner:帮你找到最便宜机票 订票不求人

    你喜欢旅行吗?在合适的时间、合适的目的地,来一场说走就走的旅行?机票就是关键!Skyscanner这款免费的手机应用,在几秒钟内比较全球600多家航空公司的航班安排、价格和时刻表,帮你节省金钱和时间。...

    小猪佩奇第二季50(小猪佩奇第二季英文版免费观看)

    Sleepover过夜Itisnighttime.现在是晚上。...

    我在民政局工作的那些事儿(二)(我在民政局上班)

    时间到了1997年的秋天,经过一年多的学习和实践,我在处理结婚和离婚的事情更加的娴熟,也获得了领导的器重,所以我在处理平时的工作时也能得心应手。这一天我正在离婚处和同事闲聊,因为离婚处几天也遇不到人,...

    夏天来了就你还没瘦?教你不节食13天瘦10斤的哥本哈根减肥法……

    好看的人都关注江苏气象啦夏天很快就要来了你是否和苏苏一样身上的肉肉还没做好准备?真是一个悲伤的故事……下面这个哥本哈根减肥法苏苏的同事亲测有效不节食不运动不反弹大家快来一起试试看吧~DAY1...

    Pursuing global modernization for peaceful development, mutually beneficial cooperation, prosperity for all

    AlocalworkeroperatesequipmentintheChina-EgyptTEDASuezEconomicandTradeCooperationZonei...

    Centuries-old tea road regains glory as Belt and Road cooperation deepens

    FUZHOU/ST.PETERSBURG,Oct.2(Xinhua)--NestledinthepicturesqueWuyiMountainsinsoutheastChi...

    15 THE NUTCRACKERS OF NUTCRACKER LODGE (CONTINUED)胡桃夹子小屋里的胡桃夹子(续篇)

    ...

    AI模型部署:Triton Inference Server模型部署框架简介和快速实践

    关键词:...

    Ftrace function graph简介(flat function)

    引言由于android开发的需要与systrace的普及,现在大家在进行性能与功耗分析时候,经常会用到systrace跟pefetto.而systrace就是基于内核的eventtracing来实...

    JAVA历史版本(java各版本)

    JAVA发展1.1996年1月23日JDK1.0Java虚拟机SunClassicVM,Applet,AWT2.1997年2月19日JDK1.1JAR文件格式,JDBC,JavaBea...

    java 进化史1(java的进阶之路)

    java从1996年1月第一个版本诞生,到2022年3月最新的java18,已经经历了27年,整整18个大的版本。很久之前有人就说java要被淘汰,但是java活到现在依然坚挺,不知道java还能活...

    学习java第二天(java学完后能做什么)

    #java知识#...

    取消回复欢迎 发表评论: