前言
组合式 API (composition API)作为 Vue3 最重要的更新内容之一,相较于 Vue2 传统的选项式 API (option API),带来了翻天覆地的变化。
开始使用组合式 API 写 Vue 组件也有大半年了,从选项式的写法切换而来,不适应的阵痛期也曾难受过。觉得通过 setup 把逻辑全部挤在一起,是混乱,是异类,还不如原来把数据、生命周期函数、props、emit 之类的东西在对象中分开声明清晰,直白,明了。到后来渐入佳境,封装自定义 hooks,自由地构建业务逻辑的时候,我才恍然大悟,不由得感叹组合式 API 的神奇。
可能使用 Vue3 的响应式 API 就是写普通组件的最佳方法!
什么是响应式 API
鉴于目前使用 Vue2 的程序员还不算少数,那就先来介绍一下响应式 API 吧。
Vue 在官网上对响应式 API 的定义是,用于 声明响应式的状态 的一系列接口集合,即我们通常在 setup() 函数、 <script setup> 语法糖、hooks 函数中使用到的诸如 ref()、reactive()、computed() 这类的 API。
通常,我们可以通过 Vue3 提供的这类 API,声明响应式变量 const bar = ref(null) ,而这些声明的响应式变量(本质上是包裹着元数据的一个对象)可以高效的追踪其中元数据的变化,并几乎实时地通过 Vue.Js 的处理,渲染到页面模板中引用对应的 Dom 位置上。
直白地来说,Vue3 的响应式 API 就是 Vue2 中选项式 API 中定义响应式数据 data 内容的另一种使用形式。
响应式 API 和 选项式 API 用法区别
Vue 官网上其实给出了更为详细的说明,感兴趣的朋友们也可以直接去看: 组合式 API 常见问答 | Vue.js (vuejs.org)
基本用法
由于 Vue 组件的写法多种多样,Vue3 也可以使用选项式 API 定义组件,主要就展示官方所推荐的——使用 <script setup> 语法糖的方式来定义组件。
直接上代码:
// Composition API with script setup
<template>
<-- 这里是模板 -->
<div> {{ a }} </div>
</template>
<script setup>
import { ref } from 'vue'
const a = ref(0)
</script>
// Option API
<template>
<-- 这里是模板 -->
<div> {{ a }} </div>
</template>
<script>
export default {
data() {
return {
a: 1
}
},
}
</script>
响应式 API 相比组合式 API 的一个可见优势便是自由,不再需要通过固定的方式来定义响应式变量。
自由的收益
除开写法上的一些显著区别,在构建编写复杂组件上,组合式 API 的自由特性也为我们带来了显著的收益。包括但不限于能够在 <script setup> 标签包裹内的任意位置,通过 const let 等方式声明响应式变量。而其中暴露在根作用域的响应式变量均会被 Vue 自动地处理为响应式数据,响应式地渲染到模板上。
// Composition API with script setup
<template>
<-- 这里是模板 -->
<div> {{ a }} </div>
</template>
<script setup>
import { ref } from 'vue'
const a = ref(0) // a 变量是一个响应式对象
const foo = () => {
const bar = ref(1)
return bar
}
const bar = foo() // bar 变量也是一个响应式对象
</script>
最佳实践:hooks 是灵魂
虽然但是,自由也代表着为所欲为,所以最好不要为所欲为😢
在最开始使用 Vue3 的时候,定义变量的位置,定义函数的位置,定义 watch computed 计算属性的位置,onMounted 这类生命周期钩子的位置,不管是社区还是团队中的开发都没有非常一致且明确的共识,混乱就在所难免了。
相较之下,大家还是在模仿着 Vue2 的选项式 API 来构建组件,按照原来固定的书写顺序,props定义、响应式数据、生命周期、方法,很难说有非常大的提升。
但随着对组合式 API 使用的深入,我自己在开发中,逐渐摸索到一种写法:将组件一部分相对独立功能的响应式还有其处理函数写在一起。例如下面的代码例子,一个组件既要实现多个计数器,又要根据其数字统计的情况,将计数的代码逻辑、统计的逻辑分开,便可以实现逻辑的解耦。
根据这一思路,便引出了我们的主角:hooks。
使用 hooks 将特定的逻辑抽离,并对组件只暴露出其所需的最小可用的变量及函数引用,Vue 官网上提供的一个文件导航组件就很好地实践了这一思路。
docs-zh-cn/assets/FileExplorer.vue at main · vuejs-translations/docs-zh-cn (github.com)
总结一下
在 Vue3 开发中应该学习的是,尽可能地使用 hooks,将各个独立模块抽象为一个个 hook,并运用最小作用域原则,仅暴露其他模块或组件需要的变量、函数。这便是响应式 API 所带来的意义。
- 高效利用响应式
- 便于最小作用域原则开发,合理暴露变量到作用域
- 模块化,代码功能、逻辑清晰
- hooks 抽象功能逻辑,复用简单(结合函数式编程的思想)