## 策略性 Suspense 边界
不要在异步组件返回 JSX 之前等待数据加载,应使用 Suspense 边界,以便在数据加载时更快地显示包装器 UI。
**错误做法(包装器被数据获取阻塞):**
tsx
async function Page() {
const data = await fetchData() // 阻塞整个页面
return (
)
}
即使只有中间部分需要数据,整个布局也会等待数据加载。
**正确做法(包装器立即显示,数据流式加载):**
tsx
function Page() {
return (
Sidebar
Header
<Suspense fallback={}>
Footer
)
}
async function DataDisplay() {
const data = await fetchData() // 仅阻塞此组件
return
{data.content}
}
侧边栏、页眉和页脚立即渲染。只有 DataDisplay 等待数据。
**替代方案(跨组件共享 Promise):**
tsx
function Page() {
// 立即开始获取,但不等待
const dataPromise = fetchData()
return (
Sidebar
Header
<Suspense fallback={}>
Footer
)
}
function DataDisplay({ dataPromise }: { dataPromise: Promise
}) {
const data = use(dataPromise) // 解包 promise
return {data.content}
}
function DataSummary({ dataPromise }: { dataPromise: Promise }) {
const data = use(dataPromise) // 复用同一个 promise
return {data.summary}
}
两个组件共享同一个 promise,因此只会发生一次请求。布局立即渲染,同时两个组件共同等待数据。
**何时不应使用此模式:**
- 布局决策所需的关键数据(影响定位)
- 首屏 SEO 关键内容
- 小型、快速的查询(Suspense 开销不划算)
- 当你想避免布局偏移(加载中 → 内容跳动)时
**权衡:** 更快的首次绘制 vs 可能的布局偏移。根据你的 UX 优先级进行选择。