Suspense

在没有Suspense组件之前是如何达到以上效果的呢

通过条件渲染:

if (isLoading) return <Spin/>
return <MyComponent>

而有了Suspense之后,做法就变了

<Suspense callback={<Spin />}>
  <MyComponent />
</Suspense>

那么Suspense是如何知道什么时候渲染Spin、什么时候渲染MyComponent的呢,

根据子组件内的异常来控制的,类似于ErrorBoundary,不同的是,Suspense捕获的异常必须是Promise,也就是说在子组件内,需要将数据请求的fetch过程,抛出对应的Erro,由Suspense捕获,捕获后对thenable对象的then方法进行回调注册。

因此,通常需要对promise的请求方法做一些改造,才能触发Suspense的回调组件渲染,官方的推荐做法是使用SWR来进行数据的请求。

import { Suspense } from "react";
import useSWR from "swr";
 
function Profile() {
  const { data } = useSWR("/api/user", fetcher, { suspense: true });
  return <div>hello, {data.name}</div>;
}
 
function App() {
  return (
    <Suspense fallback={<div>loading...</div>}>
      <Profile />
    </Suspense>
  );
}

Suspense的另一种做法是和lazy进行结合,由此可见,React.lazy内部也是对传入的Component进行了Promise的返回处理,

<Suspense fallback={<GlobalLoading />}>
  {lazy(() => import("xxx/xxx.tsx"))}
</Suspense>

在React.lazy内部,第一次执行会先抛出error,触发Suspense的callback渲染

Suspense内部的实现是采用了OffScreen组件来渲染子组件,这个组件的特性是能根据传入的mode来控制子组件的显隐,好处是能保存子组件的状态,类似于Vue的keep-alive,且拥有最低的调度优先级。

Cloud Blog

Notes on technology, with room for life.

© 2026 Lorenzo Wang