NextJS 13:Server Component包裹Client Component时如何显示进度指示器
解决Server/Client Component加载提示不显示的问题
问题原因
- Server Component异步逻辑特性:
FormLayout作为Server Component,它的async函数会在服务器端完整执行(包括等待fetch请求完成)后,才将渲染好的HTML发送到客户端。因此你写的Loading ...分支永远不会在客户端显示——服务器已经等请求结束才返回内容,且fetch成功后data至少是空对象/数组,不会触发false分支。 - Client Component props传递逻辑:
BuildingInfoForm只有在FormLayout拿到data后才会被渲染,所以它内部的data ? ... : Loading永远只会走Form分支——因为data是父组件传递的有效数据,不存在data为假的情况。
解决方案
方案1:使用App Router内置的Loading.js(推荐)
在FormLayout所在的文件夹下创建Loading.js文件,Next.js会自动在Server Component加载数据时展示这个组件:
// Loading.js export default function Loading() { return <h1>Loading ...</h1>; }
无需修改FormLayout代码,Next.js会在服务器处理异步请求时,先向客户端返回Loading组件内容,待数据加载完成后自动替换为实际组件。
方案2:将数据请求移到Client Component(用SWR/React Query)
把数据请求逻辑移到BuildingInfoForm中,用SWR或React Query管理异步状态:
// BuildingInfoForm.jsx(Client Component) 'use client'; import useSWR from 'swr'; const fetcher = async () => { const res = await fetch(`my_api`, { headers: { Accept: "application/json", "Content-Type": "application/json", "Key": `key`, }, }); if (!res.ok) throw new Error('数据加载失败'); return res.json(); }; export const BuildingInfoForm = () => { const { data, error, isLoading } = useSWR('building-info', fetcher); if (isLoading) return <h1>Loading ...</h1>; if (error) return <h1>{error.message}</h1>; return ( <Form> {/* 表单内容 */} </Form> ); };
然后简化FormLayout(无需异步):
// FormLayout.jsx(Server Component) import styles from "./style.module.css" import { BuildingInfoForm } from ".." export const FormLayout = () => { return ( <div className={styles["layout"]}> <BuildingInfoForm /> </div> ); };
注意:Access-Control-Allow-Origin是服务器响应头,不需要在请求头中设置,应删除该字段。
方案3:使用React Suspense包裹Server Component
在FormLayout的父组件(如page.js)中用Suspense包裹它,指定加载时的 fallback 内容:
// page.js import { Suspense } from 'react'; import { FormLayout } from './FormLayout'; export default function Page() { return ( <Suspense fallback={<h1>Loading ...</h1>}> <FormLayout /> </Suspense> ); }
服务器处理FormLayout异步请求时,客户端会先展示Suspense的fallback内容,直到Server Component渲染完成后替换为实际内容。
内容的提问来源于stack exchange,提问作者Ala Eddine Menai
相关产品推荐
相关产品推荐

