typescriptintermediate

Streaming with Loading UI and Suspense

Use loading.tsx and React Suspense to stream UI progressively in Next.js App Router.

typescript
// app/dashboard/loading.tsx
export default function DashboardLoading() {
  return (
    <div className="animate-pulse space-y-4">
      <div className="h-8 bg-gray-200 rounded w-1/3" />
      <div className="grid grid-cols-3 gap-4">
        {[...Array(3)].map((_, i) => (
          <div key={i} className="h-32 bg-gray-200 rounded" />
        ))}
      </div>
    </div>
  );
}

// app/dashboard/page.tsx
import { Suspense } from 'react';

async function SlowChart() {
  const data = await fetch('https://api.example.com/chart-data', {
    cache: 'no-store',
  }).then((r) => r.json());
  return <Chart data={data} />;
}

async function QuickStats() {
  const stats = await fetch('https://api.example.com/stats', {
    next: { revalidate: 60 },
  }).then((r) => r.json());
  return <StatsCards stats={stats} />;
}

export default function DashboardPage() {
  return (
    <div>
      <h1>Dashboard</h1>
      <Suspense fallback={<StatsSkeleton />}>
        <QuickStats />
      </Suspense>
      <Suspense fallback={<ChartSkeleton />}>
        <SlowChart />
      </Suspense>
    </div>
  );
}

Use Cases

  • dashboards
  • progressive loading
  • improving perceived performance

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.