Skip to content
Snippets Groups Projects
util.ts 1.25 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { cloneDeep, isEqual } from 'lodash'
    import { computed, ComputedGetter, ComputedRef, readonly, Ref, ref, watch, watchEffect } from 'vue'
    
    
    export function computedIter<T>(fn: ComputedGetter<Iterable<T>>): ComputedRef<T[]> {
      return computed(() => Array.from(fn()))
    }
    
    
    export const useId = (() => {
      let _id = 0
      return function useId(prefix = 'component') {
        return readonly(ref(`${prefix}-${_id++}`))
      }
    })()
    
    
    export function useAsyncFunction<F extends (...args: never[]) => ReturnType<F>>(
      fn: F,
    ): { isLoading: Ref<boolean>; fn: (...args: Parameters<F>) => ReturnType<F> } {
      const isLoading = ref(false)
      function wrapper(...args: Parameters<F>): ReturnType<F> {
        isLoading.value = true
        try {
          return fn(...args)
        } finally {
          isLoading.value = false
        }
      }
      return { fn: wrapper, isLoading }
    }
    
    export function useUpdatableState<T>(
      externalStateRef: Ref<T>,
      onUpdate: (value: T) => void,
      clone: (value: T) => T = cloneDeep,
    ): Ref<T> {
      const localRef = ref()
      watchEffect(() => {
        localRef.value = clone(externalStateRef.value)
      })
      watch(
        localRef,
        (newValue) => {
          if (!isEqual(newValue, externalStateRef.value)) {
            onUpdate(newValue)
          }
        },
        { deep: true },
      )
      return localRef
    }