Follow

React like hooks with Vue3 composition API :milkbear_036:

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'.`
      )
  }
}
· · Web · 0 · 0 · 1
Sign in to participate in the conversation
小森林

每个人都有属于自己的一片森林,也许我们从来不曾走过,但它一直在那里,总会在那里。迷失的人迷失了,相逢的人会再相逢。愿这里,成为属于你的小森林。