Skip to content

withAddonGroup

withAddonGroup一个异步函数依据需要进行分组,每个分组状态独立还支持并发调用。

典型场景包括:

  • 列表中每一项都有「确认 / 删除 / 提交」等操作
  • 多个 item 同时触发相同 API,但需要各自独立的 loading / error / data
  • 操作在语义上是“同一个”,但在 UI 上是“多个并行实例”

基本用法

ts
const { 
  confirm, 
  confirmGroup 
} = useAsync('confirm', confirmApi, {
  addons: [
    withAddonGroup({
      key: (args) => args[0], // 使用第一个参数作为分组 key
    }),
  ],
})

在模板中使用

vue
<template>
  <div v-for="item in items" :key="item.id">
    <button
      :loading="confirmGroup[item.id]?.loading"
      @click="confirm(item.id)"
    >
      {{ confirmGroup[item.id]?.loading ? '确认中...' : '确认' }}
    </button>
  </div>
</template>

👉 每一个 item.id 都会自动关联一个独立的 confirmGroup[item.id],不需要为每一项单独封装异步逻辑,也不需要手动管理状态映射。

数据结构

{name}Group 是一个按 key 分组响应式数据集合:

ts
confirmGroup[key]

每个 {name}Group[key] 始终包含以下字段:

ts
type GroupType<M extends (...args: any[]) => any> = {
  loading: boolean
  error: any
  arguments: Parameters<M> | undefined
  argumentFirst: Parameters<M>['0'] | undefined
  data: Awaited<ReturnType<M>> | undefined
  dataExpired: boolean
}

特点说明

{name}Group[key] 是按需生成的。如果某个 key 从未被调用过时,{name}Group[key]undefined,因此访问时需要使用可选链 ?.

ts
// ✅ 正确
confirmGroup[item.id]?.loading

// ❌ 错误(key 可能尚未存在)
confirmGroup[item.id].loading

要欺骗 ts {name}Group 包含所有 key 很困难,会造成类型与实现不一致,所以统一通过可选链访问

插件特性

1. 自动创建与同步

  • 当异步函数被调用时,对应的 {name}Group[key] 会自动创建
  • 符合该分组的请求状态(loading / error / data)会自动同步到 {name}Group[key]

2. 自动处理竞态

  • 竞态逻辑与未分组时的逻辑完全一致
  • 无需额外配置即可避免竞态问题

进阶:内存释放

⚠️ 大多数场景不需要关心内存问题

因为组件卸载会自动卸载所有关联变量。只有在以下情况才建议考虑:

  • 异步状态存在于全局或长生命周期组件中,且分组 key 会持续增长(例如长时间存在的分页、无限滚动页面)
  • 你在写一些基础组件,可以统一处理,比如分页列表组件
  • 你希望在「上下文切换」时,主动清理旧分组

此时,随着 key 数量增长,{name}Group 会随之增长。

分页场景

ts
const page = ref(1)

const { queryItem, itemGroup } = useAsyncData(
  'item',
  getItemApi,
  {
    addons: [
      withAddonGroup({
        key: (args) => args[0],   // itemId
        scope: () => page.value, // 当前页作为作用域
      }),
    ],
  }
)

page 变化时:

  • 上一个 page 下的所有 {name}Group[key] 会被自动清理

scope 不是用于区分请求,而是用于定义这些分组何时整体失效。

手动清理

ts
const {
  confirm,
  confirmGroup,
  clearConfirmGroup,
} = useAsync(
  'confirm',
  confirmApi,
  {
    addons: [withAddonGroup({ key: (args) => args[0] })],
  }
)
ts
// 清理指定 key
clearConfirmGroup('item1')

// 清理全部 group
clearConfirmGroup()

在请求未结束时清除,请求完成后会自动丢弃。

心智模型

关于内存释放,记住这两句话就够了:

  • key:区分 并行调用
  • scope:定义 这些调用的生命周期

如果不明确是否需要使用,那就不使用。只用 key,就已经覆盖了 90% 的使用场景。

其它

Released under the MIT License.