describe

In our business, we often request data asynchronously to render our pages, and for code and logic reuse we can wrap it in hooks

Technology stack

  • vue3
  • typescript
import { toRefs, reactive, onMounted } from 'vue'

type Service<R = any, P extends any[] = any[] > =(. args: P) = > Promise<R>

type OptionsType = {
  /** Whether to call */ manuallymanual? :boolean
  /** Initializes data */initialData? :any
  /** Successful callback */onSuccess? :() = > void
  /** Failed callback */onError? :(e: Error | null) = > void
  /** Other attributes */
  [propName: string] :any
}

type StateType<D> = {
  data: D
  loading: boolean
  error: Error | null
}

/**
 * useAsync
 * @param  {Promise} Pro asynchronous operation *@param  {Object} The options parameter *@param  {Boolean} [options.manual=false] Whether to call * manually@param  {Any} Options. initialData Initializes data *@param  {Function} Options. onSuccess Callback successfully *@param  {Function} Options. onError Failed callback */

export function useAsync<T = any> (pro: Service<T>, options: OptionsType = {}) {
  const {
    manual = false,
    initialData,
    onSuccess = () = > {}, // eslint-disable-line
    onError = console.log
  } = options

  const state: StateType<T> = reactive({
    data: initialData || null.error: null.loading: false
  })

  const run = async () => {
    state.error = null
    state.loading = true
    try {
      const result = await pro()
      state.data = result
      onSuccess()
    } catch (err) {
      onError(err)
      state.error = err
    }
    state.loading = false
  }

  onMounted(() = > {
    !manual && run()
  })

  // Change data actively from the outside
  function mutate(data: T) {
    state.data = data
  }
  return {
    ...toRefs(state),
    run,
    mutate
  }
}

Copy the code

use

<template>
  <ul>
    <li v-for="(item, index) in list" :key="index">{{item.name}}</li>
  </ul>
</template>
<script>
import { defineComponent, ref } from 'vue'
function getUsers() {
  return new Promise(resolve= > {
    setTimeout(() = > {
      resolve([
        { name: 'foo' },
        { name: 'bar' },
        { name: 'baz'}}]),1000)})}export default defineComponent({
  setup() {
    const { data: list } = useAsync(
      () = > {
        return getUsers()
      },
      {
        initialData: []})return {
      list
    }
  }
})
</script>
Copy the code

conclusion

Ts version source address

Js version of the source address

UseAsync uses documentation

The useAsync plugin comes from ant-simple-Pro, which has many plugins developed with vue3+ TS. Ant-simple-pro is simple, beautiful and quick to use, supporting 3 big frames.