Next.js 服务端组件及其加载

'use server'

async function ServerComponentWithTimeout() {
  await sleepMs(1000)
  return <>
    这个组件将会在 1000ms 后响应给前端
  </>
}

export async function App() {
  /**
   * 这个 await 会阻塞整个 response,
   * 一直到它完成,前端才能得到(其下的内容的)响应;
   * 且一旦它抛错,前端就会抛 500;
   * 可以 catch 错误,以避免 500
   */
  await fetch('xxx').catch(/* catch 能避免 500 */)

  /**
   * 基本同上,但无法通过 catch 错误来避免 500;
   * (try cache 也一样 500)
   * 所以你需要确保该方法不会抛错
   */
  await serverActionFunc().catch(/* catch 无效,不能避免 500 */)

  // 上面的阻塞完成之后,服务端将会流式响应下列内容

  return <>
    <>这一行文本会立即响应给客户端</>

    <Suspense fallback={<>
      当其内的异步服务端组件构建时,这一个 fallback 会立即响应给前端,
      且暂时不会触发 DOMContentLoaded,
      表现上就是浏览器 tab 栏上还能看见转圈圈
    </>}>
      {/*
        该服务端组件构建完成后,会流式地响应给前端;
        如果该组件抛 server error,会转发到最近的 error.tsx
      */}
      <ServerComponentWithTimeoutA />
    </Suspense>

    <Suspense fallback={<>
      这个 fallback 和上面那个 fallback 是一起响应给前端的
    </>}>
      {/*
        该服务端组件会和上面那个服务端组件同时发起构建;
        该服务端组件构建完成后,会流式地响应给前端;
        如果该组件抛 server error,会转发到最近的 error.tsx
      */}
      <ServerComponentWithTimeoutB />
    </Suspense>
    
    {/*
      应尽量避免或减少 ServerComponent 直接暴露,
      会阻塞**整个**页面的加载;
      如果该组件抛 server error,会转发到最近的 error.tsx;
      可以像上面那样用 Suspense 包裹;
      除非你:从业务上的确需要阻塞加载,或者你不在乎阻塞;
    */}
    <ServerComponentWithTimeoutC />

    {/*
      所有响应均已完成,此时才会触发 DOMContentLoaded,表现上就是 tab 栏不转圈圈了
      (不考虑其他组件/子组件)
    */}
  </>
}

如非特别声明,本站作品均为原创,遵循【自由转载-保持署名-非商用-非衍生 创意共享 3.0 许可证】。

对于转载作品,如需二次转载,请遵循原作许可。