Suspense

Suspense 用于处理异步组件加载时的占位显示。当子组件中包含异步内容(如懒加载组件)时,Suspense 会在加载完成前显示 fallback 内容,加载完成后自动切换为实际内容。

基本用法

tsx
import { Suspense, lazy } from 'vitarx'

// 创建一个懒加载组件
const AsyncChart = lazy(() => import('./Chart'))

function App() {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <AsyncChart />
    </Suspense>
  )
}

AsyncChart 还在加载时,页面会显示"加载中…";加载完成后,自动替换为 AsyncChart 的内容。

属性

属性类型必填说明
childrenView实际要渲染的内容,通常包含异步组件
fallbackView加载中显示的占位视图
onResolved() => void所有异步内容加载完成后的回调函数

工作原理

Suspense 内部维护一个计数器,用来追踪子组件中异步任务的数量:

  1. 当子组件中有异步内容正在加载时,计数器大于 0,显示 fallback
  2. 当所有异步内容加载完成后,计数器归零,自动切换为 children
  3. 如果子组件中没有异步内容,计数器为 0,直接显示 children

这意味着你可以在一个 Suspense 中放置多个异步组件,它会等待所有异步组件都加载完成后才切换。

onResolved 回调

onResolved 会在所有异步子内容加载完成并替换到视图后调用,适合做一些加载完成后的操作,比如隐藏全局 loading、记录日志等。

tsx
import { Suspense, lazy } from 'vitarx'

const AsyncTable = lazy(() => import('./Table'))
const AsyncChart = lazy(() => import('./Chart'))

function Dashboard() {
  return (
    <Suspense
      fallback={<div>数据加载中...</div>}
      onResolved={() => {
        console.log('所有数据加载完成')
      }}
    >
      <AsyncTable />
      <AsyncChart />
    </Suspense>
  )
}

多层嵌套 Suspense

Suspense 支持嵌套使用。内层 Suspense 只负责它自己的异步子组件,外层 Suspense 负责外层的异步子组件。内层 Suspense 完成加载后,外层的计数器才会减少。

tsx
import { Suspense, lazy } from 'vitarx'

const AsyncHeader = lazy(() => import('./Header'))
const AsyncContent = lazy(() => import('./Content'))
const AsyncSidebar = lazy(() => import('./Sidebar'))

function App() {
  return (
    // 外层 Suspense 等待 AsyncHeader
    <Suspense fallback={<div>页面加载中...</div>}>
      <AsyncHeader />
      {/* 内层 Suspense 等待 AsyncContent 和 AsyncSidebar */}
      <Suspense fallback={<div>内容区域加载中...</div>}>
        <AsyncContent />
        <AsyncSidebar />
      </Suspense>
    </Suspense>
  )
}

完整示例

下面是一个完整的示例,展示了 Suspense 配合 lazy 懒加载组件的使用:

tsx
import { Suspense, lazy, ref } from 'vitarx'

// 懒加载组件——在 Suspense 内使用时,无需指定 loading 选项
const UserProfile = lazy(() => import('./UserProfile'))
const UserPosts = lazy(() => import('./UserPosts'))

function UserPage() {
  const loaded = ref(false)

  return (
    <div>
      <h1>用户主页</h1>
      <Suspense
        fallback={<div>页面数据加载中,请稍候...</div>}
        onResolved={() => {
          loaded.value = true
          console.log('用户主页加载完成')
        }}
      >
        <UserProfile userId="123" />
        <UserPosts userId="123" />
      </Suspense>
    </div>
  )
}

INFO

lazy 组件在 Suspense 内使用时,Suspensefallback 优先级高于 lazyloading 选项,因此无需为 lazy 指定 loading。只有在 lazy 组件不在 Suspense 内使用时,loading 选项才会生效。

下一步