【vue3笔记之 ref 和 reactive 】
实现响应式数据的方法
可以使用 ref,reactive定义响应式数据,本质上就是将传入的数据包装成一个Proxy对象。
使用 reactive 必须是对象(Json/arr),如果给 reactive 传递了其他的对象,默认情况下修改对象,页面不会自动更新。但是可以通过重新赋值的形式更新页面。
<template>
<div>
<p>{{value.time}}</p>
<button @click="myFn">按钮</button>
</div>
</template>
import {reactive} from 'vue';
setup() {
let value = reactive({
time: new Date()
});
// 实现点击按钮,当前日期的天数加一
funtion myFn() {
const newValue = new Date(value.time.getTime());
newValue.setDate(value.time.getDate() + 1);
value.time = newValue;
}
return {value, myFn};
}
ref 实现对简单值的监听,本质其实还是 reactive,系统会自动根据我们给 ref 的传值将它装换成ref(xx) >>>> reactive({value: xx})
注意:
vue中<template>
使用 ref 的值不用通过value获取,但在<script><template>
中需要通过 .value 去获取 ref 定义的值;(注:Vue是根据当前数据中是否含有私有属性 __v_ref 为true来判断是不是ref类型,从而判断是否需要添加 .value。在代码中有 isRef 和 isReactive 方法去判断当前数据是什么类型的)
JS中使用ref的值必须通过value获取。
<template>
<div>
<p>{{age}}</p>
<button @click="myFn">按钮</button>
</div>
</template>
import {isRef, isReactive} from 'vue';
import {ref} from 'vue';
setup() {
let age = ref(18);
funtion myFn() {
console.log(isRef(age)); // 结果为true
console.log(isReactive(age)); // 结果为false
age.value = 666;
}
return {age, myFn};
}
递归监听
1、默认情况下,ref 和 reactive 都是递归监听
2、递归监听的弊端:如果数据量比较大,非常消耗性能(Vue3会递归取出对象每一层的值,把每层的值都包装成一个proxy对象)
非递归监听
1、只能够监听第一层,不能监听其他层
2、使用 shallowRef 和 shallowReactive方法定义非递归,shallowReactive定义的非递归对象只会给第一层包装成proxy,只要第一层数据发生变化,其他层级的也会重新渲染。第一层没有变化的话,其他层级也不会发生变化。shallowRef 定义的数据,那么vue监听的是 .value的变化,并不是第一层的变化,因为本质上shallowRef的第一层是value。triggerRef根据传入的数据,主动的更新界面。(Vue3只提供了triggerRef方法,没有triggerReactive方法,如果是reactive定义的 数据,是没有办法触发界面更新的)
递归/非递归的应用场景
一般情况下,我们使用 ref 和 reactive 递归监听即可
只有需要监听的数据量非常大的时候,才使用非递归监听 shallowRef 和 shallowReactive
扩展:toRaw() 方法专门用来获取 ref 或者 reactive 类型的原始数据,如果是获取 ref 类型的原始数据,需要在对象后面添加 .value。
获取原始数据的作用:由于 ref 和 reactive 数据类型每次修改都会被追踪并更新UI界面(消耗性能),如果有些操作不需要监听 和更新UI界面,可以先使用toRaw获取原始数据,对原始数据进行修改。