基本概念
“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数,负责管理会随时间而变化的状态。 组合式逻辑
- 封装逻辑:可以将与某一功能相关的逻辑封装在一个函数中(通常被称为“组合函数”)。
- 逻辑复用:这些组合函数可以在多个组件中复用,不需要每次都在组件内重复相同的逻辑。
- 模块化和解耦:不同的功能逻辑可以分开维护,使得组件代码更加易读、易维护。
其实基本上可以认为就是 hook,起名为 useXXX(定义和导出组合式API(Composition API)的自定义函数)。
参数
参数可以是 ref,getter,或者其他任何东西,可以通过 toValue 统一处理它们。
返回值
返回值推荐使用 ref 而不是 reactive。 因为 reactive 只对整个对象的引用保持响应性,而解构后拿到的是属性没有这种特性。
副作用
要在组件卸载的时候调钩子函数清除副作用!
onUnmounted(() => window.removeEventListener('mousemove', update))鼠标跟踪器
为了创建一个可复用的鼠标跟踪逻辑,采用 hook 分离逻辑:
// mouse.js
import { ref, onMounted, onUnmounted } from 'vue'
// 按照惯例,组合式函数名以“use”开头
export function useMouse() {
// 被组合式函数封装和管理的状态
const x = ref(0)
const y = ref(0)
// 组合式函数可以随时更改其状态。
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
// 一个组合式函数也可以挂靠在所属组件的生命周期上
// 来启动和卸载副作用
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
// 通过返回值暴露所管理的状态
return { x, y }
}注意这里返回的是两个响应式对象。由于 JS 闭包机制,即使函数执行完成,只要对内部成员的引用存在,依旧可以访问它们,因此这里返回引用后数值依旧可以正常被更新:
<script setup>
import { useMouse } from './mouse.js'
const { x, y } = useMouse()
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>异步状态
promise
一个代理,代表一个在创建 promise 时不一定已知的值,将处理程序与异步操作的最终成功值或失败原因关联起来,使得异步方法可以像同步方法一样返回值:异步方法不会立即返回最终值,而是返回一个 promise,以便在将来的某个时间点提供该值。 其拥有以下状态:
- 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled):意味着操作成功完成。
- 已拒绝(rejected):意味着操作失败。
当 promise 进行链式调用时,上一个 then返回的结果会自动作为下一个then的参数,类似这样:(promise D, (promise C, (promise B, (promise A) ) ) )。
// fetch.js
import { ref } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
fetch(url)
.then((res) => res.json())
.then((json) => (data.value = json)) //解析出json内容并赋值给ref
.catch((err) => (error.value = err))
return { data, error }
}<script setup>
import { useFetch } from './fetch.js'
const { data, error } = useFetch('...')
</script>接收响应式状态
我们希望 useFetch 在参数值改变时重新调用,这时候应当向其中传递 ref 对象或一个 getter。
// fetch.js
import { ref, watchEffect, toValue } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const fetchData = () => {
// reset state before fetching..
data.value = null
error.value = null
fetch(toValue(url))
//返回调用getter返回值的值,或是ref的.value,如果都不是就返回参数的值
.then((res) => res.json())
.then((json) => (data.value = json))
.catch((err) => (error.value = err))
}
watchEffect(() => {
fetchData()
})
return { data, error }
}watchEffect 可以立即运行一个函数,同时响应式地追踪其(响应式)依赖,并在依赖更改时重新执行。在本例中是 url 的改变触发了这个侦听器,并触发副作用函数 fetchData。 watchEffect 是一个响应式侦听器,它会自动跟踪在其回调中使用的所有响应式数据(如 url)。当这些数据变化时,它会重新运行回调,而不会创建新的侦听器。Vue 会确保只触发一个现有的 watchEffect,而不会累积多个。