组合式函数(Hooks)
组合式函数 是一个利用 Vue 的组合式API 来封装和复用有状态逻辑的函数。
鼠标跟踪器示例
ts
import { ref, onMounted, onUnmounted } from 'vue'
// 通常hooks命名以 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 }
}
vue
<template>
Mouse position is at: {{ mouseX }}, {{ mouseY }}
</template>
<script setup lang="ts">
import { useMouse } from './useMouse.ts'
const x = ref(-10)
// 当 hooks 中解构的变量与组件中变量名称冲突时,可以重命名
const { x: mouseX, y: mouseY } = useMouse()
</script>
异步状态示例
特定场景下,可能需要向 hooks 传递参数,看下面的示例:
ts
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))
.catch((err) => (error.value = err))
return { data, error }
}
vue
<script setup lang="ts">
import { useFetch } from './useFetch.ts'
const { data, error } = useFetch('/api/getUsers')
</script>
接收响应式状态
useFetch()
接收一个静态URL字符串作为输入——因此它只会执行一次 fetch 并且就此结束。
如果我们想要在 URL 改变时重新 fetch 呢?
需要将响应式状态传入组合式函数,并让它基于传入的状态来创建执行操作的侦听器。
例如,useFetch()
应该能够接收一个 ref:
ts
const url = ref('/api/getUsers')
const { data, error } = useFetch(url)
// 更新 url 的值,希望能够重新触发fetch
url.value = '/api/getUsers?id=1'
或者接受一个 getter 函数:
ts
// 当 props.id 改变时重新 fetch
const { data, error } = useFetch(() => `/posts/${props.id}`)
可以用 watchEffect()
和 toValue()
API 来重构现有的实现:
ts
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))
.then((res) => res.json())
.then((json) => (data.value = json))
.catch((err) => (error.value = err))
}
watchEffect(() => {
// 侦听器监听了 toValue(url) 的值
fetchData()
})
return { data, error }
}
提示
toValue()
是一个在 3.3 版本中新增的 API,它的设计目的是将 ref 或 getter 规范化为值:
- 如果参数是 ref,它会返回 ref 的值;
- 如果参数是 getter 函数,它会调用函数并返回其返回值;
- 否则,它会原样返回参数;
ts
// 推荐做法
import { toValue } from 'vue'
function useFeature(maybeRefOrGetter) {
// 如果 maybeRefOrGetter 是一个 ref 或 getter,将返回它的规范化值。否则原样返回。
const value = toValue(maybeRefOrGetter)
}