美文网首页
Vue3 Composition API: 对比ref和reac

Vue3 Composition API: 对比ref和reac

作者: Bachelor_a4ee | 来源:发表于2020-10-23 09:16 被阅读0次

    对比refreactive

    Vue2回顾

    首先回顾一下在Vue2中我们是如何创建一个响应式数据 (reactive data)的:

    <template>
      <img alt="Vue logo" src="./assets/logo.png" />
      <h1>{{ title }}</h1>
      <button @click="handleClick">✌</button>
    </template>
    
    <script lang="ts">
    //在lang="ts"的环境下,要在vue3中使用vue2的API,需要使用 defineComponent 包裹一下整个对象,来确保this的指向不出问题
    import { defineComponent } from 'vue';
    
    export default defineComponent({
      name: "App",
      data() {
        return {
          title: "你好,Vue3!",
        };
      },
      methods: {
        handleClick() {
          this.title = "海贼王来了";
        },
      },
    });
    </script>
    

    Vue3新特性

    ref的使用

    而在Vue3中,我们可以用Composition API: ref 来改写上述代码:

    <template>
      <img alt="Vue logo" src="./assets/logo.png" />
      <h1>{{ title }}</h1>
      <button @click="handleClick">✌</button>
    </template>
    
    <script lang="ts">
    import { defineComponent, ref } from "vue";
    
    export default defineComponent({
      name: "App",
      setup() {
        const title = ref("你好, Vue3!");
        const handleClick = () => {
          title.value = "海贼王来了";
        };
        return { title, handleClick };
      },
    });
    </script>
    

    ref 的作用就是将一个原始数据类型(primitive data type)转换成一个带有响应式特性(reactivity)的数据类型,原始数据类型共有7个,分别是:

    • String
    • Number
    • BigInt
    • Boolean
    • Symbol
    • Null
    • Undefined

    相比于Vue2,用ref 的好处就是传值时可以不用再写this

    那如果我想让一个对象(Object)也具有响应性(reactive) 这一特点呢?

    reactive的使用

    Vue3提供了一个方法:reactive (等价于Vue2中的Vue.observable() )来赋予对象(Object) 响应式的特性,那么我们可以将上述代码用对象的形式改写为:

    <template>
      <img alt="Vue logo" src="./assets/logo.png" />
      <h1>{{ data.title }}</h1>
      <button @click="data.handleClick">✌</button>
    </template>
    
    <script lang="ts">
    import { defineComponent, reactive } from "vue";
    
    export default defineComponent({
      name: "App",
      setup() {
        const data = reactive({
          title: "你好, Vue3",
          handleClick: () => {
            data.title = "海贼王来了";
          },
        });
        return { data };
      },
    });
    </script>
    

    你可能会觉得data.xxx 的写法太麻烦,那么我们可以使用es6新语法扩展运算符来简化一下:

    <template>
      <img alt="Vue logo" src="./assets/logo.png" />
      <h1>{{ title }}</h1>
      <button @click="handleClick">✌</button>
    </template>
    
    <script lang="ts">
    import { defineComponent, reactive } from "vue";
    
    export default defineComponent({
      name: "App",
      setup() {
        const data = reactive({
          title: "你好, Vue3",
          handleClick: () => {
            data.title = "海贼王来了";
          },
        });
        return { ...data };
      },
    });
    </script>
    

    Bug出现

    不出意外,你会发现这个简化后的代码竟然无效,不管怎么点按钮,页面并没有发生变化!事实上,这样写没有效果的原因就在于一个响应型对象(reactive object) 一旦被销毁或展开(如上面代码那样),其响应式特性(reactivity)就会丢失。通过类型检查我们可以知道,虽然 data.title 的值确实发生了变化,但data.title的类型只是一个普通的字符串(String) ,并不具有响应式特性(reactivity),故而页面也没有随着其值的变化而重新渲染。

    toRefs的作用

    为了解决上述问题,Vue3又提供了一个新的API:toRefs,它可以将一个响应型对象(reactive object) 转化为普通对象(plain object),同时又把该对象中的每一个属性转化成对应的响应式属性(ref)。说白了就是放弃该对象(Object)本身的响应式特性(reactivity),转而给对象里的属性赋予响应式特性(reactivity)。故而我们可以将代码修复成下面这样:

    <template>
      <img alt="Vue logo" src="./assets/logo.png" />
      <h1>{{ title }}</h1>
      <button @click="handleClick">✌</button>
    </template>
    
    <script lang="ts">
    import { defineComponent, reactive, toRefs } from "vue";
    
    export default defineComponent({
      name: "App",
      setup() {
        const data = reactive({
          title: "你好, Vue3",
          handleClick: () => {
            data.title = "海贼王来了";
          },
        });
        const dataAsRefs = toRefs(data);
        /*
        Type of dataAsRefs:
        {
            title: Ref<string>,
            handleClick: Ref<() => void>
        }
        */
        return { ...dataAsRefs };
      },
    });
    </script>   
    

    总结

    refreactive 一个针对原始数据类型,而另一个用于对象,这两个API都是为了给JavaScript普通的数据类型赋予响应式特性(reactivity)。根据Vue3官方文档,这两者的主要区别在于每个人写JavaScript时的风格不同,有人喜欢用原始数据类型(primitives),把变量单独拎出来写;而有人喜欢用对象(Object),把变量当作对象里的属性,都写在一个对象里头,比如:

    // style 1: separate variables
    let x = 0
    let y = 0
    
    function updatePosition(e) {
      x = e.pageX
      y = e.pageY
    }
    
    // --- compared to ---
    
    // style 2: single object
    const pos = {
      x: 0,
      y: 0
    }
    
    function updatePosition(e) {
      pos.x = e.pageX
      pos.y = e.pageY
    }
    

    (完)

    参考资料

    [1]:https://vue-composition-api-rfc.netlify.app/#ref-vs-reactive
    [2]:https://www.danvega.dev/blog/2020/02/12/vue3-ref-vs-reactive/
    [3]:https://coding.imooc.com/learn/list/449.html

    相关文章

      网友评论

          本文标题:Vue3 Composition API: 对比ref和reac

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