我们在深入学习Object.defineProperty和Proxy讲解过Proxy优点以及Vue3为什么改用Proxy实现响应式,同时Vue3也将一些响应式的API进行抽离,以便代码更好的复用。
我们可以使用reactive
来为JS对象创建响应式状态:
import { reactive, toRefs } from "vue";
const user = reactive({
name: 'Vue2',
age: 18,
});
user.name = 'Vue3'
reactive相当于Vue2.x中的Vue.observable
。
reactive函数只接收object和array等复杂数据类型。
对于一些基本数据类型,比如字符串和数值等,我们想要让它变成响应式,我们当然也可以通过reactive函数创建对象的方式,但是Vue3提供了另一个函数ref
:
import { ref } from "vue";
const num = ref(0);
const str = ref("");
const male = ref(true);
num.value++;
console.log(num.value);
str.value = "new str";
console.log(str.value);
male.value = false;
console.log(male.value);
ref返回的响应式对象是只包含一个名为value参数的RefImpl对象,在js中获取和修改都是通过它的value属性;但是在模板中被渲染时,自动展开内部的值,因此不需要在模板中追加.value
。
<template>
<div>
<span>{{ count }}</span>
<button @click="count ++">Increment count</button>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return {
count
}
}
}
</script>
reactive主要负责复杂数据结构,而ref主要处理基本数据结构;但是很多童鞋就会误解ref只能处理基本数据,ref本身也是能处理对象和数组的:
import { ref } from "vue";
const obj = ref({
name: "woqueqian",
age: 1,
});
setTimeout(() => {
obj.value.name = "wofuzhi";
}, 1000);
const list = ref([0, 1, 2, 3, 4]);
setTimeout(() => {
list.value.push(5);
}, 2000);
当我们处理一些大型响应式对象的property时,我们很希望使用ES6的解构来获取我们想要的值:
let book = reactive({
name: 'Learn Vue',
year: 2020,
title: 'Chapter one'
})
let {
name,
} = book
name = 'new Learn'
console.log(book.name);
但是很遗憾,这样会消除它的响应式;对于这种情况,我们可以将响应式对象转换为一组ref,这些ref将保留与源对象的响应式关联:
let book = reactive({
name: 'Learn Vue',
year: 2020,
title: 'Chapter one'
})
let {
name,
} = toRefs(book)
// 注意这里解构出来的name是ref对象
// 需要通过value来取值赋值
name.value = 'new Learn'
console.log(book.name);
对于一些只读数据,我们希望防止它发生任何改变,可以通过readonly
来创建一个只读的对象:
import { reactive, readonly } from "vue";
let book = reactive({
name: 'Learn Vue',
year: 2020,
title: 'Chapter one'
})
const copy = readonly(book);
// 对键“name”的设置操作失败:目标为只读。
copy.name = "new copy";
有时我们需要的值依赖于其他值的状态,在vue2.x中我们使用computed函数
来进行计算属性,在vue3中将computed功能进行了抽离,它接受一个getter函数,并为getter返回的值创建了一个「不可变」的响应式ref对象:
const num = ref(0);
const double = computed(() => num.value * 2);
num.value++;
// 2
console.log(double.value);
// 计算值为只读
double.value = 4
或者我们也可以使用get和set函数创建一个可读写的ref对象:
const num = ref(0);
const double = computed({
get: () => num.value * 2,
set: (val) => (num.value = val / 2),
});
num.value++;
console.log(double.value);
double.value = 8
console.log(num.value);
说完响应式api,下期我们开始说响应式侦听。