昨天跟一位同学聊天,说到:“在 Vue 中 hooks 是否可以使用 Vue 的生命周期?”
我一下就没反应过来 “Vue 中有 hooks 了吗?”。后来才明白,人家那叫Composables
(组合式函数)
1. 什么是 hooks?
hook
翻译过来是钩子的意思。hooks
作为复数,直译就是多个钩子,在开发领域中特指钩子函数。
在开发领域,最初的 hook 是和回调钩子绑定的。比如我们常说的git hooks 指的就是在 git 提交的时候所产生的多个回调钩子函数。
不过,在 React 16.8 的版本之后,React 文档中提到了React Hooks
的概念。
React Hooks
与传统 hook 的概念不太相同,他表示的是:以 use 开头的自定义函数
在 React 中,所有内置的 Hooks 和社区约定的自定义 Hooks 函数都遵循以 use 开头的命名规则
自此,hooks
的概念才进入到大部分开发者的视野中。
2. Vue 中的 “hooks”
Vue 中严格来说不存在hooks 的概念。但是,却有非常类似(也有人说是抄袭)的概念,这就是Composables
(组合式函数)
“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数。
与 React 相同,它(Composables)的命名也要求以use
开头的驼峰标识,而返回值则尽量返回以ref
包裹的响应式数据
在 Vue 的官方文档中,描述了 Composables 与 React Hooks 的关系:
3. Composables 示例
接下来,我们就通过一个鼠标跟踪器示例,来更加清楚的了解下 Composables 的应用场景。
3.1 监听鼠标位置的直接写法
如果我们要直接在组件中使用组合式 API 实现鼠标跟踪功能,它的代码会是这样:
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
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))
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>
这个代码逻辑并不复杂:
首先我们使用 ref
定义了两个响应式数据 x、y然后在 onMounted
和onUnmounted
生命周期中,完成事件的挂载和销毁通过 update 方法,修改响应式数据的值,并展示在页面中
这样的代码作用在单独的组件里,如果想要复用就比较麻烦了。因此,就可以使用Composables
3.2 使用 Composables
基于Composables
封装该逻辑:
// 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 }
}
根据以上代码所以,我们可知:
Composables 中,应尽量使用 ref
Composables 中,生命周期可正常调用,就像我们写普通的 js 一样
下面是它在组件中使用的方式:
<script setup>
import { useMouse } from './mouse.js'
const { x, y } = useMouse()
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>