Skip to content

useAsyncState - Vue 异步状态管理

通用场景:任何需要异步数据获取 + 加载状态管理的场景,核心是解决重复的模板代码问题。

具体应用:

  • 表格数据加载
  • 下拉选项获取
  • 用户信息查询
  • 搜索结果展示
  • 任何需要"请求中 → 成功/失败"状态切换的组件

解决问题:标准化异步状态管理模式,避免在每个组件中重复编写 loading、error、data 三种状态的管理代码,让开发者专注业务逻辑。

避免重复代码:

js
const loading = ref(false);
const data = ref(null);
const error = ref(null);

async function fetchData() {
  loading.value = true;
  try {
    data.value = await api();
  } catch (err) {
    error.value = err;
  } finally {
    loading.value = false;
  }
}

useAsyncState.ts

typescript
import { ref as deepRef, shallowRef } from "vue";

interface useAsyncStateOptions {
  args?: any[];
  immediate?: boolean;
  shallow?: boolean;
}

/**
 * 更深层次的编写方法,可以参考一下 vueuse的useAsyncState
 * @see https://vueuse.org/core/useAsyncState/
 */
export function useAsyncState(
  asyncFn: (...args: any) => Promise<any>,
  initialValue: any,
  options: useAsyncStateOptions = {}
) {
  const { args = [], immediate = true, shallow = false } = options;
  const state = shallow ? shallowRef(initialValue) : deepRef(initialValue);
  const loading = deepRef(false);
  const error = shallowRef();

  function run(...params: any[]) {
    const promise = asyncFn(...params);
    loading.value = true;
    promise
      .then((res: any) => {
        state.value = res;
      })
      .catch((err: any) => {
        error.value = err;
      })
      .finally(() => {
        loading.value = false;
      });
  }

  immediate && run(...args);

  return {
    state,
    loading,
    error,
    run,
  };
}

index.vue

vue
<script setup lang="ts">
import { ElTable } from "element-plus";
import { useAsyncState } from "./useAsyncState.ts";

async function mockFetch() {
  await new Promise(resolve => setTimeout(resolve, 1000));
  return [1, 2, 3, 4, 5];
}
const { state, loading } = useAsyncState(mockFetch, false);
</script>

<template>
  <ElTable :loading="loading" :state="state" />
</template>

Released under the MIT License.