React like hooks with Vue3 composition API
import { ref, readonly, UnwrapRef, provide, inject, InjectionKey } from 'vue'
export const useState = <T>(defaultValue: T): any => {
const state = ref(defaultValue)
const set = (value: T): void => {
state.value = value as UnwrapRef<T>
}
return [readonly(state), set]
}
export interface FunctionalStore<T extends object> {
(...args: any[]): T
token?: symbol
root?: T
}
export function useProvider<T extends object>(func: FunctionalStore<T>): T {
if (!func.token) func.token = Symbol('functional store')
const depends = func()
provide(func.token, depends)
return depends
}
export function useProviders(...funcs: FunctionalStore<any>[]): any {
funcs.forEach((func) => {
if (!func.token) func.token = Symbol('functional store')
provide(func.token, func())
})
}
type InjectType = 'root' | 'optional'
export function useInjector<T extends object>(func: FunctionalStore<T>, type?: InjectType): any {
const token = func.token as InjectionKey<symbol>
const root = func.root
switch (type) {
case 'optional':
return inject<T>(token) || func.root || null
case 'root':
if (!func.root) func.root = func()
return func.root
default:
if (inject(token)) {
return inject<T>(token)
}
if (root) return func.root
throw new Error(
`Hook function '${func.name}' was not provided from upper leval component by calling 'useProvider'.`
)
}
}