认识
一、认识
组合式函数 (Composables)
是一个利用 Vue
的组合式 API
来封装和复用有状态逻辑的函数。其中 组合式函数 的约定和最佳实践为:
二、规范
2.1 命名
命名
: 组合式函数约定用驼峰命名法命名,并以use
作为开头。
2.2 参数
输入参数
: 尽管其响应性不依赖 ref
,组合式函数仍可接收 ref
参数。如果编写的组合式函数会被其他开发者使用,你最好在处理输入参数时兼容 ref
而不只是原始的值。
2.3 返回值
返回值
: 推荐的约定是组合式函数始终返回一个包含多个 ref
的普通的非响应式对象,这样该对象在组件中被解构为 ref
之后仍可以保持响应性。如果我们是用 reactive
, 那么从组合式函数中返回一个 reactive
响应式对象会导致在对象的解构中丢失与组合式函数内状态的响应性连接。与之相反,ref
则可以维持这一响应性连接。
2.4 副作用
副作用
: 在组合式函数中的确可以执行副作用, 请注意以下规则:
-
确保能访问到
DOM
-
确保在
onUnmounted()
时清理副作用。
2.5 使用限制
使用限制
: 组合式函数在 <script setup>
或 setup()
钩子中,应始终被同步地调用。在某些场景下,你也可以在像 onMounted()
这样的生命周期钩子中使用他们。这个限制是为了让 Vue
能够确定当前正在被执行的到底是哪个组件实例,只有能确认当前组件实例,才能够:
-
将生命周期钩子注册到该组件实例上
-
将计算属性和监听器注册到该组件实例上,以便在该组件被卸载时停止监听,避免内存泄漏。
三、语法
四、对比
4.1 组合式函数 vs mixin
Vue 2
的用户可能会对 mixins
选项比较熟悉。它也让我们能够把组件逻辑提取到可复用的单元里。然而 mixins
有三个主要的短板:
-
不清晰的数据来源:当使用了多个
mixin
时,实例上的数据属性来自哪个mixin
变得不清晰,这使追溯实现和理解组件行为变得困难。这也是我们推荐在组合式函数中使用ref + 解构模式
的理由:让属性的来源在消费组件时一目了然。 -
命名空间冲突:多个来自不同作者的
mixin
可能会注册相同的属性名,造成命名冲突。若使用组合式函数,你可以通过在解构变量时对变量进行重命名来避免相同的键名。 -
隐式的跨
mixin
交流:多个mixin
需要依赖共享的属性名来进行相互作用,这使得它们隐性地耦合在一起。而一个组合式函数的返回值可以作为另一个组合式函数的参数被传入,像普通函数那样。
基于上述理由,我们不再推荐在 Vue 3
中继续使用 mixin
。保留该功能只是为了项目迁移的需求和照顾熟悉它的用户。
4.2 组合式函数 vs 无渲染组件
组合式函数相对于无渲染组件的主要优势是: 组合式函数不会产生额外的组件实例开销。当在整个应用中使用时,由无渲染组件产生的额外组件实例会带来无法忽视的性能开销。
我们推荐在纯逻辑复用时使用组合式函数,在需要同时复用逻辑和视图布局时使用无渲染组件。
4.3 组合式函数 vs React Hooks
React Hooks
在 Render BeginWork
递阶段, 遇到函数组件 Fiber
, 执行函数组件, 在执行过程中, React
按照 Hook
调用的顺序遍历组件内部所有 Hook
。也就是说, React Hooks
在组件每次更新时都会重新调用。并且, 由于 React Hooks
的实现方式, Mount
阶段和 Update
中的 Hooks
是不同的逻辑。因此, Hooks
有严格的调用顺序,并不可以写在条件分支中。因为, 有可能在其中一次的渲染中, 因为一个 hook
没有执行, currentHook.next
与 将要执行的 hook
明显是不对应的, 造成代码错误。 其中, 基于依赖项的 Hooks
具有闭包问题, 需要传入正确的依赖数组, 或者需要通过 useRef
来保持状态。
Vue
组合函数 仅会在 setup()
或者 <script setup>
中调用一次, 组合式 API
也并不限制调用顺序,还可以有条件地进行调用。针对依赖项的 Hooks
, Vue
的响应性系统运行时会自动收集计算属性和侦听器的依赖,因此无需手动声明依赖, 不会存在闭包问题。
因此, Vue
组合函数 具有后发优势, 基于 React Hooks
的设计理念, 结合 Vue
自身响应式机制, 实现了一种更好用的 Hooks
。