美文网首页
Vue 3.0 响应性API(一)

Vue 3.0 响应性API(一)

作者: Joymerry | 来源:发表于2023-09-20 20:56 被阅读0次

    说起响应性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,共同进步。

    相关文章

      网友评论

          本文标题:Vue 3.0 响应性API(一)

          本文链接:https://www.haomeiwen.com/subject/ajjxcltx.html