Suspense(实验性功能)
注意:Vue Query 的 Suspense 模式属于实验性功能,与 Vue 自身的 Suspense 一样。这些 API 将发生变更,除非你将 Vue 和 Vue Query 的版本均锁定在相互兼容的补丁级版本,否则不应在生产环境中使用。
Vue Query 也可与 Vue 新的 Suspense API 配合使用。
为此,你需要用 Vue 提供的 Suspense 组件包裹可挂起(suspendable)组件:
HTML
1<script setup>2import SuspendableComponent from './SuspendableComponent.vue'3</script>4 5<template>6 <Suspense>7 <template #default>8 <SuspendableComponent />9 </template>10 <template #fallback>11 <div>Loading...</div>12 </template>13 </Suspense>14</template>并将可挂起组件中的 setup 函数改为 async。随后即可使用 vue-query 提供的异步 suspense 函数(useQuery 和 useInfiniteQuery 均返回该函数):
HTML
1<script>2import { defineComponent } from 'vue'3import { useQuery } from '@tanstack/vue-query'45const todoFetcher = async () =>6 await fetch('https://jsonplaceholder.cypress.io/todos').then((response) =>7 response.json(),8 )9export default defineComponent({10 name: 'SuspendableComponent',11 async setup() {12 const { data, suspense } = useQuery({13 queryKey: ['todos'],14 queryFn: todoFetcher,15 })16 await suspense()1718 return { data }19 },20})21</script>suspense() 的解析逻辑
- 若查询尚无数据,或其数据已过期,则会拉取该查询,并在拉取完成时以结果解析。这通常发生在查询函数执行完毕时,但也可能更早,例如在
experimental_streamedQuery返回首个数据块后,或在拉取进行中由setQueryData设置了数据时。 - 若数据为新鲜状态,则立即解析,不重新拉取。
- 当查询被禁用(
enabled: false)时,它会等待查询启用后再解析;因此,若查询始终处于禁用状态,则永远不会解析。在服务端,这会阻塞渲染,请参阅 SSR。 - 若拉取失败,则以错误状态的查询结果解析。仅当
throwOnError为(或返回)true时,它才会以错误拒绝。
错误处理
由于 suspense() 默认以错误结果解析,因此拉取失败后组件仍会渲染,并可从查询中读取 error。若希望由父组件统一处理错误,请设置 throwOnError: true。此时 suspense() 将以错误拒绝,错误将从 async setup 中向外抛出,你可在 Suspense 的父组件中使用 onErrorCaptured 捕获该错误:
HTML
1<script setup>2import { onErrorCaptured, ref } from 'vue'3import SuspendableComponent from './SuspendableComponent.vue'45const error = ref(null)67onErrorCaptured((err) => {8 error.value = err9 return false10})11</script>12 13<template>14 <div v-if="error">Something went wrong: {{ error.message }}</div>15 <Suspense v-else>16 <template #default>17 <SuspendableComponent />18 </template>19 <template #fallback>20 <div>Loading...</div>21 </template>22 </Suspense>23</template>拉取时渲染 vs 边渲染边拉取
开箱即用情况下,Vue Query 在 suspense 模式下天然适配 拉取时渲染(Fetch-on-render) 方案,无需额外配置。这意味着:当你的组件尝试挂载时,会触发查询拉取并挂起,但仅在你导入并挂载这些组件之后才发生。若你想进阶采用 边渲染边拉取(Render-as-you-fetch) 模型,我们建议在路由回调和/或用户交互事件中实现 Prefetching,以便在组件挂载前、甚至在其父组件导入或挂载之前就启动查询加载。