【Vue-Day5】ref及reactive的使用
本文介绍了Vue3中ref和reactive创建响应式数据的区别与使用。ref可定义基本类型和对象类型数据,返回RefImpl对象,需通过.value访问;reactive仅用于对象类型,返回Proxy对象。文章详细对比了两者的特性:ref更通用,而reactive处理深层对象更高效;同时指出reactive重新分配对象会失去响应式的问题,并提供了使用Object.assign的解决方案。最后总结
这是一篇普通大学生的学习记录帖,学习Vue3之前学过一些html,css,javascript的基础知识,希望可以通过记录博客对知识进行每日总结。
目录
1.ref既可以定义基本类型数据,也可以定义对象类型数据。reactive只可以定义对象类型数据。
3.reactive重新分配一个新对象,会失去响应式(可以使用Object.assign去整体替换)
解决办法:使用Object.assign(target,sources)方法解决重新分配对象问题
前言
上一篇中我们讲到setup里创建的数据不是响应式的,那么如何让数据变成响应式的呢?
这就是 ref() 函数的作用:定义响应式数据。
ref 既可以定义基本类型的响应式数据(比如字符串,数字),也可以定义对象类型的响应式数据。还有一个函数reactive()也可以定义对象类型的响应式数据。但总的还是ref更重要一些,接下来我们讲讲ref()的使用。
一.ref创建基本类型的响应式数据
先从vue库中引用ref函数,再去使用。
语法:let 变量名 = ref("初始值"),把你想要变成响应式变量的初始值直接放到ref里,这个变量就变成响应式变量了!代码如下:
<template>
<div class="person">
<div>姓名:{{ name }}</div> //在模板里直接用name,无需.value
<div>年龄:{{ age }}</div> //模板里的响应式数据自动给你.vale了
<div>地址:{{ address }}</div>
</div>
</template>
<script lang="ts" setup name='Person'>
import { ref } from 'vue'; //从库中引入ref函数
let name = ref('图图'); //用ref创建响应式数据
let age = ref('8'); //此时name,age是响应式数据
let address = "翻斗花园"; //address不是响应式数据
console.log(name); //在控制台输出一下看看会得到什么信息
console.log(age);
console.log(address);
function changename() {
name.value = '小黑'; //操作ref对象时需要.value
}
</script>

从控制台输出我们可以看到他给我们返回了一个RefImpl的对象,这就是ref对象,而address没有使用ref,因此它只是一个普通变量。并且如果我们想要在JS中操作这个响应式数据,需要使用他的.value属性。
对于
let name = ref('图图')来说,name不是响应式的,name.value是响应式的。但在模板中不需要.value,直接使用即可。
二.ref创建对象类型的响应式数据
先从vue库中引用ref函数,再去使用。
和创建基本类型一样,使用 ref 直接包裹对象即可创建响应式数据。
let car = ref({brand:'奔驰',price:'10'}); //定义响应式对象
let games = ref([ //定义响应式数组
{ id: 1, name: '英雄联盟' },
{ id: 2, name: '王者荣耀' },
{ id: 3, name: '原神' }
]);
此时,car和games 是一个响应式数据(ref 对象),其 .value 属性指向该对象。访问 / 修改对象属性时,需通过 .value 操作。
<template>
<div class="person">
<div>姓名:{{ name }}</div>
<div>年龄:{{ age }}</div>
//模板中同样不使用.value
<div>{{ name }}的爱车:{{ car .brand}}, 价格:{{ car .price }}</div>
<div>{{ name }}爱玩的游戏:</div>
<button @click="changeGame">修改游戏</button>
<button @click="changePrice">修改车价</button>
<ul>
<li v-for="game in games" :key="game.id"> {{ game.name }}</li>
</ul>
</div>
</template>
<script lang="ts" setup name='Person'>
import { ref } from 'vue';
let name = ref('图图');
let age = ref('8');
let car = ref({brand:'奔驰',price:10}); //定义响应式对象
let games = ref([ //定义响应式数组
{ id: 1, name: '英雄联盟' },
{ id: 2, name: '王者荣耀' },
{ id: 3, name: '原神' }
]);
function changePrice(){
car.value.price += 10 //JS中需要使用.value拿到对象里的响应式属性进行增改操作
}
function changeGame(){
games.value[0].name = "贪吃蛇" //数组需要先拿到响应式属性再加索引下标
}
</script>
三.ref和reactive的区别
除了ref可以定义对象类型的响应式数据,还有一个函数reactive()也可以定义对象类型的响应式数据。如果ref接收的是对象类型,内部其实也是调用了reactive函数。
1.ref既可以定义基本类型数据,也可以定义对象类型数据。reactive只可以定义对象类型数据。
2.返回对象不同(RefImpl对象和Proxy对象)
当我们使用ref定义一个响应式对象,和用reactive定义一个响应式对象,他们在控制台返回的返回的对象其实是不同的。ref返回的是RefImpl对象,reactive返回的是Proxy对象。(Proxy 是 JavaScript 中一个强大的内置对象,用于创建一个对象的代理。)

图中可以看到,红色用ref创建的基本类型数据返回的是RefImpl对象,value值正常是8。黄色用reactive创建的对象类型数据返回的是Proxy对象。绿色用ref创建的对象类型的数据返回的虽然还是RefImpl,但value值是用的调用Proxy。
总结:ref本质上会将对象类型数据自动转换为reactive代理对象(即ref内部通过reactive实现对象的响应式)。因此:
- 对于对象类型,
ref和reactive的底层响应式机制一致(基于 Proxy),都能追踪对象属性的新增 / 删除 / 修改。- 但
ref返回的是 Ref 对象(需通过.value访问),而reactive直接返回代理对象。
3.reactive重新分配一个新对象,会失去响应式(可以使用Object.assign去整体替换)
当我们用reactive创建一个响应式对象时,单独修改属性,这个属性是响应式的,但要给他重新分配一个对象(把他的属性值全部修改掉),他就不是响应式的了。在页面点击修改车的按钮页面无反应。
<script lang="ts" setup name='Person'>
import { ref , reactive } from 'vue';
let car = reactive({brand:'奔驰',price:10}); //用reactive定义响应式对象
function changeBrand(){
car.brand = "宝马" //修改对象属性值,是响应式的
}
function changePrice(){
car.price += 10 //修改对象属性值,是响应式的
}
function changeCar(){
car = {brand:'奥迪',price:20} //整体替换对象,不是响应式的
}
</script>
解决办法:使用Object.assign(target,sources)方法解决重新分配对象问题
Object.assign(target,sources) 是 JavaScript 中用于合并对象的内置方法,它可以将一个或多个源对象的属性复制到目标对象,并返回合并后的目标对象。主要用于对象的浅拷贝或属性合并。
使用方法:当你要替换掉car整个对象属性,就把car放到target位置,把你要替换的属性放到sources位置:
function changeCar(){
Object.assign(car, {brand:'奥迪',price:20}); //此时car对象引用未变,仍然是响应式的
}
总结:
- ref 既可以定义基本类型数据,也可以定义对象类型数据。
- reactive 只可以定义对象类型数据,如果对象层级较深,就用reactive。
- ref 创建的变量必须使用.value。
- reactive 会重新分配一个对象,会失去响应式,使用Object.assign(target,sources)方法解决。
最后
如果这篇文章对你有帮助的话就点个赞吧!
更多推荐
所有评论(0)