Vue 3.0 响应性API(一)

说起响应性api,我们不得不谈到reactive与ref。

一、reactive

  1. 什么是reactive?
  • reactive是Vue3中提供的实现响应式数据的方法
  • 在Vue2中响应式数据是通过defineProperty来实现的,而在Vue3中响应式数据是通过ES6的Proxy来实现的
  1. reactive的注意点:
  • reactive参数必须是对象(json/arr)
import { reactive } from 'vue';
export default {
    setup(){
      /*
      *参数必须是对象
      */
      let state = reactive({
          age: 19
      })
      return {state}
    }
}
  • 如果给reactive传递其他对象
    默认情况下修改对象,界面不会自动更新
    如果想更新,可以通过重新赋值的方式
import { reactive } from 'vue';
export default {
    setup(){
      /*
      *参数必须是对象
      */
      // 非json/arr类对象
      let state = reactive({
        time : new Date()
      })
      function myFunc(){
          // 直接修改之前的数据,页面显示不会刷新
          // state.time.setDate(state.time.getDate() + 1);    
        
          // 计算之后,直接赋值,页面显示会更新
          const newTime = new Date(state.time.getTime());
          newTime.setDate(state.time.getDate() + 1);
          state.time = newTime
          console.log(state)
      }
      return {state, myFunc}
    }
}

二、ref

  1. 什么是ref?
  • ref和reactive一样,也是用来实现响应式数据的方法
  • 由于reactive必须传递一个对象,所以导致在企业开发中,如果我们只想让某个变量实现响应式的时候会非常麻烦,所以Vue3就给我们提供了ref方法,实现对简单值的监听
  1. ref本质:
  • ref底层的本质其实还是reactive
    系统会自动根据我们给ref传入的值将它转换成reactive
/*
*ref是key为value,value为xx的reactive
*/
ref(xx) -> reactive({value:xx})
  1. ref注意点
  • 在Vue中使用ref的值不用通过value获取
    如果是通过ref创建的数据,那么在template中使用的时候不用通过.value来获取,因为Vue会自动帮我们添加.value
  • JS中使用ref的值必须通过value获取
<template>
    <!--  模版中使用不需要.value,因为Vue已经自动帮我们做了,
      如果自己添加.value,实际值相当于age.value.value-->
    <p>{{age}}</p>
</template>
<script>
import { ref } from 'vue';
export default {
    let age = ref(10)
    function myFunc(){  
      // 不在template中,Vue不会帮我们添加.value,所以必须添加.value
      age.value = 11;
    }
    return {age,myFunc}
}

三、ref和reactive区别

  1. 虽然说ref的底层是一个reactive,但是其实它们还是有一些区别的。
  • ref和reactive的区别:
    如果在template里使用的是ref类型的数据,那么Vue会自动帮我们添加.value
    如果在template里使用的是reactive类型的数据,那么Vue不会自动帮我们添加.value
  1. Vue如何决定是否需要自动添加.value的
  • Vue在解析数据之前,会自动判断这个数据是否是ref类型的,如果是就自动添加.value,如果不是就不添加
  1. Vue是如何判断当前的数据是否是ref类型的?
  • 通过当前数据的__v_ref的私有属性来判断的
  • 如果有这个私有属性,并且取值为true,那么就代表是一个ref类型的数据


    打印ref对象
  • 我们自己也是可以判断数据是否是ref类型,但是我们不能通过访问数据的私有属性__v_ref来判断,但是Vue提供了一个isRef()的对应方法
<template>
    <p>{{age}}</p>
</template>
<script>
import { ref , isRef } from 'vue';
export default {
    let age = ref(10)
    function myFunc(){  
      age.value = 11;
      // 这里返回数据的详细信息,如上图“打印ref对象”所示
      console.log(age)
      // isRef方法返回一个Boolean值
      console.log(isRef(age))
    }
    return {age,myFunc}
}
  1. 同理,Vue也提供了isReactive()方法判断是否是reactive类型

四、递归监听

  1. 递归监听
  • 默认情况下,无论是通过ref还是reactive都是递归监听
    无论数据嵌套多少层,都可以监听到数据变化
  1. 递归监听存在的问题
  • 如果数据量比较大,非常消耗性能
    为什么说它非常消耗性能呢,我们说过,Vue3.0为了实现响应性,它是通过Proxy实现的,所以为了实现递归监听,每一层数据都包装成Proxy对象,也就是数据嵌套的越深,Proxy对象就越多,这本身是非常消耗性能的
<template>
    <p>{{state.four}}</p>
</template>
<script>
import { reactive } from 'vue';
export default {
    // 多层数据,reactive会进行递归监听
    let state = reactive({
        one : 'one',
        gf:{
            two : 'two',
            f:{
                three : 'three',
                s : {
                  four : 'four'
                }
           }
        }
    })
        
    function myFunc(){
      state.four = 'haha';
      console.log(state);
      console.log(state.gf);
      console.log(state.gf.f);
      console.log(state.gf.f.s);
    }
    return {state,myFunc}
}

代码执行的结果:


递归监听(将每层数据包装成Proxy对象)

五. 非递归监听

  1. 既然有递归监听,为什么要非递归监听呢?
  • 正如上面说的,递归监听是非常消耗性能的,所以才会有非递归监听来解决这个问题,但并不是说,非递归监听就可以取代递归监听,接下来我们进一步了解非递归监听,我们就知道这两种监听在应用中是相得益彰的,各有利弊
  1. 什么是非递归监听?
  • 非递归监听是只监听数据的第一层,不会监听数据其他层
  1. 如果创建非递归监听呢?
    ref -> shallowRef
    reactive -> shallowReactive
    如果说ref、reactive是专门创建递归监听数据,那么shallowRef、shallowReactive就是专门创建非递归监听数据
  2. 非递归监听是怎么实现监听数据变化的?
  • 因为只监听第一层数据,所以如果数据第一层不发生变化,我们是监听不到变化的,要想实现响应性,我们必须保证第一层数据值重新赋值(即发生变化)
  • 我们打印数据会发现,第一层数据是Proxy对象,其他层数据并不是
<template>
    <p>{{state.one}}</p>
</template>
<script>
import { shallowReactive } from 'vue';
export default {
    // 多层数据,shallowReactive会进行非递归监听
    let state = shallowReactive({
        one : 'one',
        gf:{
            two : 'two',
            f:{
                three : 'three',
                s : {
                  four : 'four'
                }
           }
        }
    })
        
    function myFunc(){
      state.one = 'haha';
      console.log(state);
      console.log(state.gf);
      console.log(state.gf.f);
      console.log(state.gf.f.s);
    }
    return {state,myFunc}
}
非递归监听
  • 注意点:
    如果是通过shallowRef创建数据,那么Vue监听的是.value的变化,value才是真正的第一层数据
  1. triggerRef()
  • 如果我们想直接更改不是第一层数据的值,让页面发生变化,这时候就需要用triggerRef()
  • 根据你传入的数据,主动去更新页面
<template>
    <p>{{state.four}}</p>
</template>
<script>
import { shallowRef, triggerRef } from 'vue';
export default {
    // 多层数据,shallowRef会进行非递归监听
    let state = shallowRef({
        one : 'one',
        gf:{
            two : 'two',
            f:{
                three : 'three',
                s : {
                  four : 'four'
                }
           }
        }
    })
        
    function myFunc(){
      state.four = 'haha';
          triggerRef(state);
    }
    return {state,myFunc}
}
  • 注意点:
    Vue3只提供了triggerRef方法,没有提供triggerReactive方法
  1. 应用场景
    一般情况下我们使用 ref和reactive即可
    只有在需要监听的数据量比较大的时候,我们才使用shallowRef/shallowReactive

六、shallowRef的本质

之前我们说过ref的本质就是reactive(ref -> reactive)

/*
*ref的本质就是reactive
*/
ref(10) -> reactive({value:10})
/*
* shallowRef的本质就是shallowReactive
*/
shallowRef(10) -> shallowReactive({value:10})

所有如果用shallowRef创建的数据,它监听的是.value的变化
因为底层的本质上value才是第一层

总结:关于响应性API的东西还有很多,接下来我们一起探索Vue 3.0,共同进步。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容