介绍
创建一种在多个组件中使用的组合函数。
import { createSharedComposable, useMouse } from '@vueuse/core'
const useSharedMouse = createSharedComposable(useMouse)
// CompA.vue
const { x, y } = useSharedMouse()
// CompB.vue - will reuse the previous state and no new event listeners will be registered
const { x, y } = useSharedMouse()
源码
// tryOnScopeDispose/index.ts
import { getCurrentScope, onScopeDispose } from 'vue-demi'
import type { Fn } from '../utils'
/**
* Call onScopeDispose() if it's inside an effect scope lifecycle, if not, do nothing
*
* @param fn
*/
export function tryOnScopeDispose(fn: Fn) {
if (getCurrentScope()) {
onScopeDispose(fn)
return true
}
return false
}
// createSharedComposable/index.ts
import type { EffectScope } from 'vue-demi'
import { effectScope } from 'vue-demi'
import { tryOnScopeDispose } from '../tryOnScopeDispose'
import type { AnyFn } from '../utils'
/**
* Make a composable function usable with multiple Vue instances.
*
* @see https://vueuse.org/createSharedComposable
*/
export function createSharedComposable<Fn extends AnyFn>(composable: Fn): Fn {
let subscribers = 0
let state: ReturnType<Fn> | undefined
let scope: EffectScope | undefined
const dispose = () => {
subscribers -= 1
if (scope && subscribers <= 0) {
scope.stop()
state = undefined
scope = undefined
}
}
return <Fn>((...args) => {
subscribers += 1
if (!state) {
scope = effectScope(true)
state = scope.run(() => composable(...args))
}
tryOnScopeDispose(dispose)
return state
})
}
和 createGlobalState 一样使用了 effectScope 来实现。区别是在 onScopeDispose 中执行 scope.stop() 停止副作用域。
思考
和 createGlobalState 的区别
createGlobalState 目的是创建全局状态,而 createSharedComposable 是为了创建共享组合函数,在没有组件引用时释放副作用域。
采用 tryOnScopeDispose 替换 onUnmounted
组件卸载时会释放组件当前的副作用域,只要有组件引用了该组合函数,就不会释放。因此新创建了以副作用域,tryOnScopeDispose 是在当前副作用域释放时(组件卸载时)执行,dispose 函数就是在记录是否是最后一个引用改组合函数的组件卸载并且释放副作用域。
释放副作用域的时机
最后一个引用共享函数的组件卸载时才释放副作用域,官网文档上说 createSharedComposable 是用于共享组合函数,其实也可以用于共享状态,只是这个状态不是全局的,当没有组件引用时副作用才释放。