「这是我参与2022首次更文挑战的第38天,活动详情查看:2022首次更文挑战」。
Vue 3引入了Composition API,其灵感来自React Hooks,它将允许基于函数的方式编写组件,可以将逻辑封装到组合函数中。一个功能所定义的所有api会放在一起(更加的高内聚,低耦合)。
这样即使项目复杂,功能多,也可以快速定位到这个功能所用到的所有API,而不像vue2 Options API 中一个功能所用到的API都是分散的。
Vue核心团队将组件Composition API描述为“一套附加的、基于函数的api,允许灵活地组合组件逻辑”。
首先我们看下如何在vue2中是如何构建组件的。
Vue 2构建组件
在 Vue 2 中,我们使用 Options API来构建组件,下面是一个计数器组件。
<template>
<div>
<h2>Counter Options API</h2>
<p>Count: {{ count }}</p>
<p>2^Count: {{ countPow }}</p>
<button @click="increment()">Increase Count</button>
<button @click="incrementBy(5)">Increase Count by 5</button>
<button @click="decrement()">Decrease Count</button>
</div>
</template>
<script>
export default {
props: {
initialValue: {
type: Number,
default: 0,
},
},
emits: ['counter-update'],
data: function () {
return {
count: this.initialValue,
};
},
watch: {
count: function (newCount) {
this.$emit('counter-update', newCount);
},
},
computed: {
countPow: function () {
return this.count * this.count;
},
},
methods: {
//增加
increment() {
this.count++;
},
//减少
decrement() {
this.count--;
},
//叠加
incrementBy(count) {
this.count += count;
},
},
mounted: function () {
console.log('Options API counter mounted');
},
};
</script>
复制代码
这个简单的计数器组件包括多个基本的 Vue 功能:
- 使用一个
count
数据属性,该属性将该initialValue
属性用作其初始值。 countPow
作为计算属性,它计算count
值的 2 次方。- 如果计数值已更改,则发出计数器更新事件的观察者。
- 修改
count
值的多种方法。 - 如果触发了安装的生命周期钩子,就会写下一条console.log信息。
Vue 3 Composition API 构建组件
从 Vue 3 开始,我们可以额外使用 Composition API 来构建 Vue 组件。当然,Composition API 是完全可选的,仍然可以在 Vue 3 中使用 Options API。
Composition API 是一组 API,允许我们使用导入的函数而不是声明选项来编写 Vue 组件。它是一个涵盖以下 API 的总称:
- Reactivity API,例如
ref()
andreactive()
,它允许我们直接创建反应状态、计算状态和观察者。 - Lifecycle Hooks,例如
onMounted()
和onUnmounted()
,它允许我们以编程方式挂钩到组件生命周期。 - Dependency Injection,即
provide()
andinject()
,它允许我们在使用 Reactivity API 的同时利用 Vue 的依赖注入系统。
<script lang="ts">
import { ref, onMounted, computed, watch } from 'vue';
export default {
props: {
initialValue: {
type: Number,
default: 0,
},
},
emits: ['counter-update'],
setup(props, context) {
const count = ref(props.initialValue);
const increment = () => {
count.value += 1;
};
const decrement = () => {
count.value -= 1;
};
const incrementBy = (value: number) => {
count.value += value;
};
const countPow = computed(() => count.value * count.value);
watch(count, (value) => {
context.emit('counter-update', value);
});
onMounted(() => console.log('Composition API counter mounted'));
return {
count,
increment,
decrement,
incrementBy,
countPow,
};
},
};
</script>
复制代码
上面的代码所有 Composition API 组件的入口点都是新的设置方法。它在组件创建之前和 props 解决后执行。该函数返回一个对象,并且它的所有属性都暴露给组件的其余部分。
我们可以使用该reactive
方法从 JavaScript 对象创建反应状态。或者,我们可以使用ref
使独立的原始值(例如,字符串、数字或布尔值)具有响应性:
import { reactive, ref } from 'vue';
const state = reactive({
count: 0
})
console.log(state.count); // 0
const count = ref(0);
console.log(count.value); // 0
复制代码
该ref
对象只包含一个名为value
的属性,它可以访问属性值。
Vue 3 还提供了不同的新方法,例如computed
, watch
, 或者onMounted
我们可以在我们的setup
方法中使用它们来实现我们在 Options API 组件中使用的相同逻辑。
提取合成函数
可以通过将计数器逻辑提取到一个独立的组合函数useCounter来进一步改进我们的 Vue 组件代码:
import { ref, computed, onMounted } from 'vue';
export default function useCounter(initialValue: number) {
const count = ref(initialValue);
const increment = () => {
count.value += 1;
};
const decrement = () => {
count.value -= 1;
};
const incrementBy = (value: number) => {
count.value += value;
};
const countPow = computed(() => count.value * count.value);
onMounted(() => console.log('useCounter mounted'));
return {
count,
countPow,
increment,
decrement,
incrementBy,
};
}
复制代码
在 Vue 2 中,Mixins主要用于在组件之间共享代码。但是他们有几个问题:
- 不能将参数传递给 mixin' 来改变它的逻辑,这大大降低了它的灵活性。
- 当每个 mixin 中的属性合并到同一个组件中时,可能会发生属性名称冲突。
- 如果一个组件使用多个 mixin,那么哪些属性来自哪个 mixin 并不一定很明显。
组合 API 解决了所有这些问题。
Composition API 的优点:
- 通过组合 API 带来的关注点分离功能,代码更具可读性和可维护性。
- 没有更多
this
关键字,因此我们可以使用箭头函数并使用函数式编程。 - 我们只能访问我们从
setup
方法返回的东西,使东西更具可读性。 - Vue 3 是用 TypeScript 编写的,完全支持 Composition API。
- 组合函数可以很容易地进行单元测试。
下图是官方文档演示的大型组件,不同的颜色对逻辑重点进行分组,并且比较了Options API 和 Composition API:
Vue Composition API与React Hooks区别
Vue Composition API 提供与 React Hooks 相同级别的逻辑组合能力,但有一些重要区别。
首先,在react中,每次组件更新时都会重复调用React hooks。这样产生了非常多warning,还会导致性能优化问题,严重影响开发体验。
相比之下,Vue Composition API 金调用setup()
或script setup
编码一次,这样让代码更符合使用习惯,无需担心过时的闭包,Vue Composition API调用时对调用顺序也不敏感,还可以附带条件。