Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan) · Pelajaran

Prapemaparan Separa: Rangka Statik, Ruang Dinamik

Gabungkan rangka statik yang diprapaparkan dengan kawasan dinamik yang distrim menggunakan model PPR.

Pelajaran 3 daripada 413 langkah

Prapemaparan Separa: Rangka Statik, Ruang Dinamik ialah pelajaran Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan) percuma di CoddyKit. Ini ialah pelajaran 3 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan), dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan) merangkumi sejumlah 4 pelajaran.

Apakah Prapaparan Separa?

Prapaparan Separa (PPR) ialah model pemaparan yang diperkenalkan dalam Next.js 14+ dan diperhalus dalam Next.js 15, yang membolehkan satu laluan menyampaikan kandungan statik dan dinamik secara serentak.

Dengan pemaparan tradisional, anda perlu memilih satu:

  • Statik (SSG/SSR dengan cache penuh) — pantas, tetapi data diperibadikan mungkin lapuk
  • Dinamik (SSR pada setiap permintaan) — segar, tetapi Masa ke Bait Pertama lebih lambat

PPR menghapuskan pertukaran ini. Pada masa binaan, Next.js memprapaparkan cangkerang statik (reka letak, unsur rangka kerja, kandungan di bahagian atas paparan) dan menyediakan ruang kosong tempat data dinamik akan distrim pada masa permintaan — semuanya daripada satu fail laluan.

Mendayakan PPR dalam Next.js 15

PPR ialah ciri pilihan. Dayakannya dalam next.config.ts dengan bendera experimental.ppr.

Dalam Next.js 15, anda juga boleh mendayakannya secara berperingkat — mengikut laluan — menggunakan eksport konfigurasi segmen laluan experimental_ppr dan bukannya mendayakannya secara global.

Selepas didayakan, rangka kerja menganalisis pepohon laluan anda pada masa binaan, lalu memisahkan cangkerang statik daripada subpepohon yang mengandungi API dinamik (cookies(), headers(), searchParams, noStore() dan sebagainya).

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    ppr: true, // enable globally
    // OR use 'incremental' to opt in per-route
    // ppr: 'incremental',
  },
};

export default nextConfig;

Memilih Laluan untuk PPR Secara Berperingkat

Apabila anda menetapkan ppr: 'incremental' dalam next.config.ts, segmen laluan individu mesti memilih untuk turut serta secara jelas dengan mengeksport pemalar experimental_ppr yang ditetapkan kepada true.

Ini sesuai untuk memindahkan aplikasi besar secara beransur-ansur — hanya halaman yang anda anotasi akan menerima pemprosesan PPR, manakala halaman lain berkelakuan seperti sebelumnya.

Eksport tersebut mesti berada terus dalam fail halaman atau reka letak segmen yang ingin anda prapaparkan secara separa.

// app/dashboard/page.tsx
// Opt this route into Partial Prerendering
export const experimental_ppr = true;

export default function DashboardPage() {
  return (
    <main>
      <h1>Dashboard</h1>
      {/* static shell renders at build time */}
      {/* dynamic holes are defined below with Suspense */}
    </main>
  );
}

Cangkerang Statik

Cangkerang statik ialah segala-galanya dalam laluan anda yang tidak bergantung pada API dinamik. Next.js memprapaparkan dan menyimpannya dalam cache pada masa binaan (sedia untuk CDN), lalu menyampaikannya serta-merta — sebelum sebarang panggilan pangkalan data dibuat.

Kandungan cangkerang statik yang lazim termasuk:

  • Reka letak halaman dan unsur rangka kerja navigasi
  • Bahagian wira dengan teks yang ditetapkan terus atau diambil secara statik
  • Antara muka rangka / ruang letak untuk ruang dinamik
  • Komponen Pelayan yang hanya membaca daripada sistem fail atau fetch statik dengan cache penuh

Inti pati pentingnya: cangkerang statik disampaikan sebagai strim HTML yang diprapaparkan, manakala ruang dinamik terus dimuatkan secara selari.

// app/store/page.tsx
import { Suspense } from 'react';
import ProductListSkeleton from '@/components/ProductListSkeleton';
import DynamicCart from '@/components/DynamicCart';
import StaticHero from '@/components/StaticHero'; // no dynamic APIs

export const experimental_ppr = true;

export default function StorePage() {
  return (
    <div>
      {/* Static shell — prerendered at build time */}
      <StaticHero />
      <nav>Store Navigation</nav>

      {/* Dynamic hole — streams in at request time */}
      <Suspense fallback={<ProductListSkeleton />}>
        <DynamicCart />
      </Suspense>
    </div>
  );
}

Mentakrifkan Ruang Dinamik dengan Suspense

Ruang dinamik ialah mana-mana subpepohon yang dibungkus dalam sempadan <Suspense> dan mengandungi komponen yang menggunakan API Next.js dinamik.

Next.js menggunakan sempadan Suspense sebagai sempadan antara statik dan dinamik. Segala-galanya di dalam sempadan itu dikecualikan daripada cangkerang yang diprapaparkan, sebaliknya distrim sebagai bahagian berasingan apabila data tersedia.

Peraturan penting:

  • Komponen Pelayan dinamik mestilah komponen async yang melakukan pengambilan data — bukan sekadar pembungkus
  • Anda mesti menyediakan fallback kepada sempadan Suspense; sandaran ini dimasukkan ke dalam cangkerang statik supaya pengguna melihatnya serta-merta
  • Berbilang sempadan Suspense yang bebas menghasilkan berbilang ruang bebas yang distrim secara selari
// components/DynamicCart.tsx
import { cookies } from 'next/headers'; // marks this subtree as dynamic

async function DynamicCart() {
  const cookieStore = await cookies();
  const sessionId = cookieStore.get('session_id')?.value;

  const cart = sessionId
    ? await fetchCart(sessionId) // DB call at request time
    : null;

  return (
    <aside>
      <h2>Your Cart</h2>
      {cart ? (
        <ul>
          {cart.items.map((item) => (
            <li key={item.id}>{item.name} — ${item.price}</li>
          ))}
        </ul>
      ) : (
        <p>Your cart is empty.</p>
      )}
    </aside>
  );
}

export default DynamicCart;

async function fetchCart(sessionId: string) {
  // simulated DB call
  return { items: [{ id: 1, name: 'Widget', price: 9.99 }] };
}

Berbilang Ruang Dinamik yang Bebas

Salah satu kelebihan terbesar PPR ialah anda boleh mempunyai berbilang ruang dinamik yang bebas dalam satu laluan. Setiap sempadan Suspense menstrim kandungannya secara berasingan, jadi panggilan pangkalan data yang lambat di satu bahagian tidak menghalang bahagian lain.

Bayangkan papan pemuka dengan:

  • ucapan pengguna (membaca cookies())
  • widget statistik langsung (membaca daripada pangkalan data analitik yang lambat)
  • suapan aktiviti terkini (membaca daripada jadual yang berbeza)

Ketiga-tiganya distrim secara selari selepas cangkerang statik disampaikan, lalu memberikan pengalaman yang dipertingkatkan secara beransur-ansur dan bukannya satu penantian yang panjang.

// app/dashboard/page.tsx
import { Suspense } from 'react';
import UserGreeting from '@/components/UserGreeting';
import LiveStats from '@/components/LiveStats';
import ActivityFeed from '@/components/ActivityFeed';
import {
  GreetingSkeleton,
  StatsSkeleton,
  FeedSkeleton,
} from '@/components/Skeletons';

export const experimental_ppr = true;

export default function DashboardPage() {
  return (
    <main className="dashboard-grid">
      <h1>Welcome to your Dashboard</h1> {/* static */}

      {/* Three independent holes — stream in parallel */}
      <Suspense fallback={<GreetingSkeleton />}>
        <UserGreeting />
      </Suspense>

      <Suspense fallback={<StatsSkeleton />}>
        <LiveStats />
      </Suspense>

      <Suspense fallback={<FeedSkeleton />}>
        <ActivityFeed />
      </Suspense>
    </main>
  );
}

Apakah yang Menjadikan Komponen Dinamik?

Next.js mengesan penggunaan dinamik secara automatik dengan mengimbas API tertentu. Komponen Pelayan dianggap dinamik (dikecualikan daripada cangkerang statik) apabila menggunakan:

  • cookies() atau headers() daripada next/headers
  • prop searchParams pada halaman
  • unstable_noStore() atau fetch dengan cache: 'no-store'
  • Mana-mana API yang memilih untuk tidak menggunakan Cache Data pada masa permintaan

Jika API dinamik digunakan di luar sempadan Suspense, keseluruhan laluan kembali kepada pemaparan dinamik penuh — PPR dilumpuhkan untuk laluan tersebut. Sentiasa bungkus komponen dinamik dalam Suspense untuk mengekalkan cangkerang statik.

// components/UserGreeting.tsx
import { cookies, headers } from 'next/headers';

export async function UserGreeting() {
  // Both of these mark this component as dynamic
  const cookieStore = await cookies();
  const headersList = await headers();

  const userId = cookieStore.get('user_id')?.value;
  const userAgent = headersList.get('user-agent') ?? 'Unknown';

  const user = userId ? await fetchUser(userId) : null;

  return (
    <div>
      <p>Hello, {user?.name ?? 'Guest'}!</p>
      <small>Browsing via: {userAgent.split('/')[0]}</small>
    </div>
  );
}

async function fetchUser(id: string) {
  // imagine a real DB query here
  return { name: 'Mehmet' };
}

Sandaran Rangka ialah Sebahagian daripada Cangkerang Statik

Prop fallback bagi setiap sempadan Suspense disertakan dalam cangkerang statik yang diprapaparkan. Ini bermakna pengguna menerima antara muka rangka tanpa sebarang kelewatan — dengan kependaman yang sama seperti halaman yang sepenuhnya statik.

Reka rangka anda supaya dimensi dan reka letaknya hampir sepadan dengan kandungan akhir. Ini meminimumkan Anjakan Reka Letak Terkumpul (CLS) apabila kandungan dinamik distrim masuk dan menggantikan rangka.

Strategi rangka yang baik:

  • Padankan lebar dan tinggi kandungan sebenar sedekat mungkin
  • Gunakan animasi CSS (denyutan/kilauan) untuk menyampaikan keadaan pemuatan
  • Elakkan ruang letak yang kelihatan seperti data sebenar — pengguna mungkin menganggapnya sebagai kandungan
// components/Skeletons.tsx
export function StatsSkeleton() {
  return (
    <div className="animate-pulse space-y-2 p-4 rounded-lg bg-gray-100">
      <div className="h-4 bg-gray-300 rounded w-1/3" />
      <div className="h-8 bg-gray-300 rounded w-1/2" />
      <div className="h-4 bg-gray-300 rounded w-2/3" />
    </div>
  );
}

export function FeedSkeleton() {
  return (
    <ul className="animate-pulse space-y-3">
      {Array.from({ length: 5 }).map((_, i) => (
        <li key={i} className="flex gap-3 items-center">
          <div className="h-8 w-8 rounded-full bg-gray-300" />
          <div className="flex-1 h-4 bg-gray-300 rounded" />
        </li>
      ))}
    </ul>
  );
}

export function GreetingSkeleton() {
  return <div className="animate-pulse h-6 bg-gray-300 rounded w-40" />;
}

PPR berbanding SSR Penstriman Tradisional

Mudah untuk mengelirukan PPR dengan SSR penstriman biasa (menggunakan Suspense tanpa PPR). Inilah perbezaan utamanya:

  • SSR penstriman (tanpa PPR) — Keseluruhan respons dipaparkan pada pelayan ketika permintaan dibuat. Bahagian statik dipaparkan dengan pantas, manakala bahagian dinamik distrim kemudian. Namun, HTML awal tidak pernah dicache di pinggir CDN — setiap permintaan sampai ke pelayan anda.
  • PPR — Cangkerang statik diprapaparkan pada masa binaan dan disampaikan serta-merta dari pinggir CDN. Hanya ruang dinamik yang mencetuskan pelaksanaan pelayan pada masa permintaan. Anda mendapat penyampaian statik sepantas CDN serta data dinamik yang segar.

PPR pada asasnya ialah: penyampaian statik CDN + penstriman pada masa permintaan yang digabungkan dalam satu laluan.

Membaca searchParams Tanpa Menjejaskan PPR

Dalam Next.js 15, searchParams pada komponen Halaman ialah nilai dinamik — membacanya menyebabkan keseluruhan halaman tidak lagi menggunakan pemaparan statik. Dengan PPR, anda tidak boleh membaca searchParams secara terus dalam komponen halaman (di luar sempadan Suspense).

Sebaliknya, hantarkan searchParams sebagai prop kepada komponen yang dibungkus dalam Suspense. Ini mengekalkan cangkerang halaman luar sebagai statik, sambil membolehkan komponen dalam membaca parameter pertanyaan pada masa permintaan.

// app/search/page.tsx
import { Suspense } from 'react';
import SearchResults from '@/components/SearchResults';
import SearchResultsSkeleton from '@/components/SearchResultsSkeleton';

export const experimental_ppr = true;

type SearchPageProps = {
  searchParams: Promise<{ q?: string; page?: string }>;
};

export default function SearchPage({ searchParams }: SearchPageProps) {
  // Do NOT await searchParams here — that would make the shell dynamic.
  // Pass the Promise into the dynamic hole instead.
  return (
    <div>
      <h1>Search</h1> {/* static shell */}

      <Suspense fallback={<SearchResultsSkeleton />}>
        {/* SearchResults awaits searchParams inside the Suspense boundary */}
        <SearchResults searchParamsPromise={searchParams} />
      </Suspense>
    </div>
  );
}

Mengesahkan Tingkah Laku PPR dalam Pembangunan

Semasa next dev, PPR disimulasikan tetapi halaman tidak benar-benar dibina terlebih dahulu — setiap permintaan akan dirender semula. Untuk melihat tingkah laku PPR sebenar, anda perlu menjalankan binaan pengeluaran:

  • next build — menjana cangkerang statik pada masa binaan
  • next start — menyampaikan output pengeluaran

Selepas binaan selesai, semak jadual output yang dicetak pada terminal. Laluan dengan PPR ditandai dengan simbol ◐ (bulatan separa berisi) yang menunjukkan prapaparan separa — berbeza daripada laluan yang sepenuhnya statik (○) dan sepenuhnya dinamik (λ).

Anda juga boleh memeriksa direktori .next/server/app untuk mencari fail HTML yang dipaparkan terlebih dahulu serta muatan RSC berasingan bagi bahagian dinamik.

Semakan Pengetahuan: Peraturan Sempadan PPR

Seorang pembangun mendayakan PPR pada suatu laluan dan membungkus komponen dinamiknya dalam sempadan Suspense. Antara pernyataan berikut, yang manakah menerangkan dengan betul perkara yang berlaku jika pembangun memanggil cookies() secara langsung di dalam komponen Page (di luar mana-mana sempadan Suspense)?

Imbas Kembali: Prapaparan Separa dalam Amalan

Dalam pelajaran ini, anda telah meneroka Partial Prerendering (PPR) — model Next.js 15 yang menggabungkan penyampaian statik sepantas CDN dengan penstriman dinamik pada masa permintaan.

Perkara utama:

  • Dayakan PPR secara global melalui experimental.ppr: true dalam next.config.ts, atau bagi setiap laluan dengan export const experimental_ppr = true
  • Cangkerang statik (segala-galanya di luar sempadan Suspense) dipaparkan terlebih dahulu pada masa binaan dan disampaikan serta-merta daripada CDN
  • Setiap sempadan Suspense mentakrifkan bahagian dinamik — kandungan sandarannya dimasukkan ke dalam cangkerang, manakala kandungannya distrim pada masa permintaan
  • API dinamik (cookies(), headers(), searchParams, pengambilan no-store) mesti berada di dalam sempadan Suspense untuk mengekalkan cangkerang
  • Berbilang sempadan Suspense yang berasingan distrim secara selari, sekali gus memaksimumkan prestasi yang dirasai pengguna
  • Bina dengan next build dan cari simbol ◐ untuk mengesahkan bahawa PPR aktif pada sesuatu laluan

PPR ialah penghubung antara pilihan statik dan dinamik yang sebelum ini bersifat sama ada satu atau yang lain — gunakannya untuk menyampaikan cangkerang dengan pantas serta data terkini daripada fail laluan yang sama.

Percuma untuk bermula

Pelajari TypeScript dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
22
Pelajaran
88

Soalan Lazim

Adakah pelajaran “Prapemaparan Separa: Rangka Statik, Ruang Dinamik” percuma?

Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan), termasuk “Prapemaparan Separa: Rangka Statik, Ruang Dinamik”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan) merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Prapemaparan Separa: Rangka Statik, Ruang Dinamik”?

Gabungkan rangka statik yang diprapaparkan dengan kawasan dinamik yang distrim menggunakan model PPR. Anda berlatih Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan) menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan)?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan) di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 3 daripada 4.

Berapa lamakah pelajaran “Prapemaparan Separa: Rangka Statik, Ruang Dinamik” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan) ini?

Ya. Setiap pelajaran Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan) menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Sempadan Suspense dan Penstriman Tahap Komponen
  2. Mereka Bentuk loading.tsx dan Rangka yang Bermakna
  3. Prapemaparan Separa: Rangka Statik, Ruang Dinamik
  4. Perangkap Penstriman: Anjakan Susun Atur dan Air Terjun
← Kembali ke Tindanan Penuh Next.js 15 (Penghala Aplikasi + Tindakan Pelayan)