Vue3 Composition API ref和reactive的区别

本文对比Vue2与Vue3中创建响应式数据的方式,重点探讨Vue3的ref和reactive API。ref适用于原始数据类型,赋予单一属性响应式,而reactive则将整个对象转换为响应式。文章通过示例和错误分析解释了ref和reactive的使用场景及相互补充的关系,旨在帮助开发者理解这两个核心API的区别。
摘要由CSDN通过智能技术生成

Vue3 Composition API: 对比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

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值