为什么要用组合式API呢
- 用原始方式写,业务逻辑会过于分散;
- 使用组合式API,可以把同一业务逻辑的代码放在一起;
使用组合式API写代码
1、所有逻辑都放在setup函数,它的第一个参数是props对象(setup函数中的props是响应式的,不能用ES6解构,会消除prop的响应性)setup文档
2、通过ref、reactive、toRef来创建响应式数据;
3、视图要用到的变量、方法为setup函数返回的对象属性;
4、watch、computed是个函数;
5、生命周期钩子写法微调,xyz变成onXyz,比如mounted变成onMounted,而且created和beforeCreate不再需要,这是因为setup函数本身就是围绕created和beforeCreate来进行的,所以不需要再定义它们,这两个钩子里编写的任何代码都直接写在setup函数里即可;
setup函数中要使用
context.emit
(context是setup的第二个参数),不能在setup函数里使用this.$emit
,你可以在methods里使用this.$emit
,但是我们以后在vue3中尽量不使用methods,要使用setup;
响应式API
ref
- ref和reactive一样, 也是用来实现响应式数据的,不过它是传递一个简单值
- ref底层的本质其实还是reactive,系统会自动根据我们给ref传入的值将它转换成
ref(xx) -> reactive({value:xx})
; - 在JS中我们要用
xx.value
,但是在HTML模板中,直接使用xx
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
reactive
传递一个对象,把它变成响应式数据(结合toRef代码一起看)
toRef
为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接。
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
fooRef.value++
console.log(state.foo) // 2
state.foo++
console.log(fooRef.value) // 3
toRefs
将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref;
一般用于setup参数props的结构居多,比如:const {title} = toRefs(props)
const state = reactive({
foo: 1,
bar: 2
})
const stateAsRefs = toRefs(state)
/*
stateAsRefs 的类型:
{
foo: Ref<number>,
bar: Ref<number>
}
*/
// ref 和原始 property 已经“链接”起来了
state.foo++
console.log(stateAsRefs.foo.value) // 2
stateAsRefs.foo.value++
console.log(state.foo) // 3
- 响应式状态解构
import { reactive, toRefs } from 'vue'
const book = reactive({
author: 'Vue Team',
year: '2020',
title: 'Vue 3 Guide',
description: 'You are reading this book right now ;)',
price: 'free'
})
let { author, title } = toRefs(book)
title.value = 'Vue 3 Detailed Guide' // 我们需要使用 .value 作为标题,现在是 ref
console.log(book.title) // 'Vue 3 Detailed Guide'
完整示例
<template>
有{{ count }}次
<button @click="onAddCount">click</button>
<h1>{{ helloText }}</h1>
</template>
<script>
import { onMounted, ref, computed, watch } from "vue";
function getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(Math.floor(Math.random() * 5));
}, 3000);
});
}
export default {
props: ["msg"],
setup(props) {
let count = ref(0);
const getCount = async () => {
count.value = await getData();
};
const onAddCount = () => {
count.value++;
};
onMounted(getCount);
let name = ref("win");
let helloText = computed(() => {
return props.msg + " " + name.value;
});
watch(count, (newvalue, oldvalue) => {
let result = "";
for (let i = 0; i < count.value; i++) {
result += name.value;
}
console.log(result, "result");
name.value = result;
});
return {
count,
onAddCount,
name,
helloText,
};
},
};
</script>