Warunkowe renderowanie slotów dla pulpitów i kart
Steruj sekcjami pulpitu i widokami kart, mapując segmenty tras na równoległe sloty.
Warunkowe renderowanie slotów dla pulpitów i kart to bezpłatna lekcja Next.js 15 Fullstack (App Router + Server Actions) na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Next.js 15 Fullstack (App Router + Server Actions), a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Next.js 15 Fullstack (App Router + Server Actions) zawiera 4 lekcji w sumie.
Czym są trasy równoległe?
Next.js 15 wprowadza trasy równoległe — mechanizm układu, który pozwala jednocześnie renderować wiele stron w tym samym układzie, z których każda znajduje się we własnym nazwanym slocie.
Jest to idealne rozwiązanie dla pulpitów, na których niezależne sekcje, takie jak panel analityczny, kanał zespołu i pasek boczny powiadomień, mają wczytywać się równolegle i niezależnie.
- Sloty definiuje się za pomocą konwencji folderów
@slotNamewewnątrz segmentu układu - Każdy slot jest przekazywany jako właściwość do nadrzędnego pliku
layout.tsx - Sloty renderują się równolegle — jeden może przesyłać zawartość strumieniowo, podczas gdy inny jest już w pełni gotowy
Sloty można traktować jak nazwane otwory w układzie, które router jednocześnie wypełnia różnymi poddrzewami tras.
Struktura folderów dla slotów równoległych
Aby utworzyć równoległe sloty, umieść foldery @slotName bezpośrednio wewnątrz folderu segmentu trasy. Każdy folder slotu działa jak własne, małe drzewo tras.
Typowy dashboard może wyglądać tak:
app/dashboard/layout.tsx— odbiera wszystkie propsy slotówapp/dashboard/@analytics/page.tsx— slot analitycznyapp/dashboard/@team/page.tsx— slot kanału zespołuapp/dashboard/@notifications/page.tsx— slot powiadomień
Foldery slotów nie wpływają na adres URL. Adres pozostaje /dashboard, a wszystkie trzy sloty są renderowane jednocześnie.
// File: app/dashboard/layout.tsx
// TypeScript interface showing slot props
interface DashboardLayoutProps {
children: React.ReactNode;
analytics: React.ReactNode;
team: React.ReactNode;
notifications: React.ReactNode;
}
export default function DashboardLayout({
children,
analytics,
team,
notifications,
}: DashboardLayoutProps) {
return (
<div className="dashboard-grid">
<main className="col-span-2">{children}</main>
<aside className="analytics-panel">{analytics}</aside>
<aside className="team-panel">{team}</aside>
<aside className="notifications-panel">{notifications}</aside>
</div>
);
}Plik domyślny: obsługa niedopasowanych slotów
Gdy przechodzisz do adresu URL, który nie pasuje do podtrasy slotu, Next.js musi wiedzieć, co wyrenderować w tym slocie. Bez wartości zastępczej cały layout zakończyłby działanie błędem 404.
Rozwiązaniem jest plik default.tsx znajdujący się w każdym folderze slotu. Działa on jako widok zastępczy, gdy slot nie ma aktywnego dopasowania dla bieżącego adresu URL.
- Umieść plik
default.tsxw każdym folderze@slotName - Może zwracać
null, aby niczego nie renderować, albo szkielet/wartość zastępczą - Dzięki temu pozostałe sloty działają nawet wtedy, gdy jeden z nich nie ma aktywnej podtrasy
// File: app/dashboard/@notifications/default.tsx
// Renders nothing when this slot has no active route match
export default function NotificationsDefault() {
return null;
}
// File: app/dashboard/@analytics/default.tsx
// Could render a skeleton instead
export default function AnalyticsDefault() {
return (
<div className="animate-pulse bg-gray-100 rounded-lg h-48" />
);
}Warunkowe renderowanie slotów za pomocą Server Components
Komponent layoutu otrzymuje wszystkie sloty jako propsy — oznacza to, że może Pan/Pani zastosować logikę warunkową bezpośrednio w layoucie, aby pokazywać lub ukrywać sloty na podstawie danych po stronie serwera, ról użytkowników albo flag funkcji.
Ponieważ layout.tsx jest domyślnie Server Component, można wykonywać asynchroniczne pobieranie danych bezpośrednio w nim, aby podjąć tę decyzję.
- Pobrać rolę bieżącego użytkownika z bazy danych lub sesji
- Warunkowo dołączać albo wykluczać propsy slotów z renderowanego wyniku
- Nie jest wymagany JavaScript po stronie klienta do sterowania widocznością
// File: app/dashboard/layout.tsx
import { getCurrentUser } from '@/lib/auth';
interface DashboardLayoutProps {
children: React.ReactNode;
analytics: React.ReactNode;
team: React.ReactNode;
}
export default async function DashboardLayout({
children,
analytics,
team,
}: DashboardLayoutProps) {
const user = await getCurrentUser();
const isAdmin = user?.role === 'admin';
return (
<div className="dashboard-grid">
<main>{children}</main>
{isAdmin && <aside>{analytics}</aside>}
<aside>{team}</aside>
</div>
);
}Budowanie dashboardu z kartami za pomocą równoległych tras
Równoległe trasy są szczególnie przydatne w przypadku interfejsów z kartami. Zamiast używać stanu po stronie klienta do śledzenia aktywnej karty, można przypisać każdą kartę do segmentu URL, dzięki czemu stan karty staje się częścią adresu URL.
Takie podejście zapewnia:
- Adresy URL, które można udostępniać — użytkownicy mogą dodać konkretną kartę do zakładek
- Nawigację między kartami za pomocą przycisków wstecz/dalej przeglądarki
- Niezależne stany ładowania dla każdej karty dzięki Suspense
- Treść kart renderowaną na serwerze, bez kosztu hydratacji logiki kart
Pasek kart staje się zestawem komponentów <Link> wskazujących różne podtrasy w obrębie slotu.
// File: app/dashboard/@tabs/layout.tsx
// Shared tab navigation rendered inside the @tabs slot
import Link from 'next/link';
interface TabsLayoutProps {
children: React.ReactNode;
}
export default function TabsLayout({ children }: TabsLayoutProps) {
return (
<div>
<nav className="flex gap-2 border-b mb-4">
<Link
href="/dashboard/overview"
className="tab-link"
>
Overview
</Link>
<Link
href="/dashboard/revenue"
className="tab-link"
>
Revenue
</Link>
<Link
href="/dashboard/users"
className="tab-link"
>
Users
</Link>
</nav>
<div className="tab-content">{children}</div>
</div>
);
}Mapowanie segmentów tras na strony kart
Każda karta odpowiada plikowi page.tsx zagnieżdżonemu w slocie @tabs. Segment URL automatycznie staje się selektorem aktywnej karty — nie jest potrzebny stan w JavaScript.
Dla dashboardu pod adresem /dashboard ze slotem @tabs:
app/dashboard/@tabs/overview/page.tsx— aktywna pod adresem/dashboard/overviewapp/dashboard/@tabs/revenue/page.tsx— aktywna pod adresem/dashboard/revenueapp/dashboard/@tabs/users/page.tsx— aktywna pod adresem/dashboard/users
Adres URL nadrzędnego layout.tsx pozostaje taki sam (/dashboard/*), a tylko slot @tabs aktualizuje swoją zawartość.
// File: app/dashboard/@tabs/revenue/page.tsx
import { getRevenueData } from '@/lib/data';
export default async function RevenueTab() {
const data = await getRevenueData();
return (
<section>
<h2 className="text-xl font-semibold mb-4">Revenue Overview</h2>
<dl className="grid grid-cols-3 gap-4">
<div>
<dt className="text-sm text-gray-500">Monthly Recurring</dt>
<dd className="text-2xl font-bold">
${data.mrr.toLocaleString()}
</dd>
</div>
<div>
<dt className="text-sm text-gray-500">Annual Run Rate</dt>
<dd className="text-2xl font-bold">
${data.arr.toLocaleString()}
</dd>
</div>
<div>
<dt className="text-sm text-gray-500">Churn Rate</dt>
<dd className="text-2xl font-bold">{data.churnRate}%</dd>
</div>
</dl>
</section>
);
}Wyróżnianie aktywnej karty za pomocą usePathname
Aby wizualnie wskazać aktywną kartę, należy porównać bieżący adres URL z właściwością href każdej karty. Hook usePathname() z next/navigation udostępnia bieżącą ścieżkę po stronie klienta.
Ponieważ pasek kart musi być interaktywny (odczytuje bieżący adres URL), musi być Client Component. Można pozostawić tylko pasek nawigacji jako Client Component, a całą treść kart zachować jako Server Components.
- Oznaczyć plik nawigacji kart dyrektywą
'use client' - Użyć
usePathname()do wykrywania aktywnego segmentu - Zastosować klasy warunkowe na podstawie dopasowania
'use client';
// File: app/dashboard/@tabs/_components/TabNav.tsx
import Link from 'next/link';
import { usePathname } from 'next/navigation';
const tabs = [
{ href: '/dashboard/overview', label: 'Overview' },
{ href: '/dashboard/revenue', label: 'Revenue' },
{ href: '/dashboard/users', label: 'Users' },
];
export function TabNav() {
const pathname = usePathname();
return (
<nav className="flex gap-1 border-b">
{tabs.map((tab) => {
const isActive = pathname === tab.href;
return (
<Link
key={tab.href}
href={tab.href}
className={`px-4 py-2 text-sm font-medium ${
isActive
? 'border-b-2 border-blue-600 text-blue-600'
: 'text-gray-500 hover:text-gray-700'
}`}
>
{tab.label}
</Link>
);
})}
</nav>
);
}Używanie Suspense do niezależnego ładowania slotów
Jedną z największych zalet równoległych slotów jest to, że każdy slot jest przesyłany strumieniowo niezależnie. Poszczególne sloty można opakować w granice <Suspense>, aby wolny slot nie blokował renderowania szybkiego.
Eliminuje to typowy problem dashboardów, w którym jedno wolne wywołanie API zamraża całą stronę.
- Owinąć każdy slot we własny komponent
<Suspense>w layoucie - Każdy slot wyświetla własny szkielet ładowania podczas pobierania danych
- Szybkie sloty pojawiają się natychmiast, a wolne są przesyłane strumieniowo po przygotowaniu
- Nie jest potrzebny plik
loading.tsx— Suspense zapewnia szczegółową kontrolę
// File: app/dashboard/layout.tsx
import { Suspense } from 'react';
import { AnalyticsSkeleton } from '@/components/skeletons';
interface DashboardLayoutProps {
children: React.ReactNode;
analytics: React.ReactNode;
team: React.ReactNode;
notifications: React.ReactNode;
}
export default function DashboardLayout({
children,
analytics,
team,
notifications,
}: DashboardLayoutProps) {
return (
<div className="grid grid-cols-3 gap-4">
<main className="col-span-2">
<Suspense fallback={<p>Loading main...</p>}>
{children}
</Suspense>
</main>
<div className="space-y-4">
<Suspense fallback={<AnalyticsSkeleton />}>
{analytics}
</Suspense>
<Suspense fallback={<p>Loading team...</p>}>
{team}
</Suspense>
<Suspense fallback={null}>
{notifications}
</Suspense>
</div>
</div>
);
}Warunkowe sloty na podstawie parametrów zapytania
Czasami potrzebna jest kontrola widoczności slotu za pomocą parametrów zapytania, a nie segmentów ścieżki — na przykład przełączanie panelu szczegółów za pomocą ?panel=details.
W Server Components można uzyskać dostęp do parametrów zapytania za pomocą propu searchParams w plikach page.tsx albo użyć useSearchParams() w Client Components.
- Przekazać
searchParamszpage.tsxdo layoutu albo użyć Server Action - W layoucie odbierać parametry zapytania za pośrednictwem warstwy danych strony, a nie bezpośrednio (layouty nie otrzymują searchParams)
- Czystszy wzorzec: użyć własnego
page.tsxslotu do odczytu searchParams i warunkowego renderowania zawartości
// File: app/dashboard/@details/page.tsx
// Conditionally renders based on ?panel=details
interface DetailsPageProps {
searchParams: Promise<{ panel?: string }>;
}
export default async function DetailsPanel({
searchParams,
}: DetailsPageProps) {
const { panel } = await searchParams;
if (panel !== 'details') {
return null;
}
return (
<aside className="border-l pl-4">
<h3 className="font-semibold">Details Panel</h3>
<p className="text-sm text-gray-600">
Expanded details visible when ?panel=details is present.
</p>
</aside>
);
}Łączenie równoległych tras z Server Actions do obsługi stanu kart
Server Actions naturalnie współpracują z kartami opartymi na równoległych trasach. Można użyć Server Action do bezpośredniej modyfikacji danych na stronie karty, a następnie polegać na Next.js, który ponownie zweryfikuje dane i wyrenderuje ponownie tylko dotknięty slot — nie całą stronę.
Zapewnia to płynny UX: użytkownik przesyła formularz w karcie, akcja jest wykonywana na serwerze, slot ponownie przesyła strumieniowo świeże dane, a wszystkie pozostałe sloty pozostają bez zmian.
- Zdefiniować Server Action za pomocą
'use server'w osobnym pliku albo w kodzie inline - Wywołać
revalidatePathlubrevalidateTag, aby unieważnić pamięć podręczną danych - Ponownie pobierany i renderowany jest tylko odpowiedni slot
// File: app/dashboard/@tabs/users/actions.ts
'use server';
import { revalidatePath } from 'next/cache';
import { db } from '@/lib/db';
export async function deactivateUser(userId: string): Promise<void> {
await db.user.update({
where: { id: userId },
data: { isActive: false },
});
// Only the users tab data is invalidated
revalidatePath('/dashboard/users');
}
// File: app/dashboard/@tabs/users/page.tsx (partial)
// import { deactivateUser } from './actions';
//
// <form action={deactivateUser.bind(null, user.id)}>
// <button type="submit">Deactivate</button>
// </form>Miękka nawigacja i zachowywanie stanu slotów
Podczas przechodzenia między kartami lub sekcjami dashboardu za pomocą Next.js <Link> router wykonuje miękką nawigację. Oznacza to, że:
- Ponownie pobierane są tylko sloty, których segment trasy uległ zmianie
- Sloty z niezmienionymi trasami zachowują istniejący wyrenderowany wynik i stan Reacta
- Pozycja przewijania w niezmienionych slotach zostaje zachowana
To kluczowa przewaga nad tradycyjnymi implementacjami kart wykorzystującymi stan po stronie klienta — otrzymuje się nawigację sterowaną adresem URL bez kosztu ponownego renderowania całego drzewa strony przy każdym przełączeniu karty.
Twarda nawigacja (pełne przeładowanie strony) resetuje wszystkie sloty, dlatego w dashboardzie z równoległymi trasami należy zawsze używać <Link> do przechodzenia między kartami.
Sprawdzenie wiedzy: niedopasowane sloty
Ma Pan/Pani layout dashboardu z trzema równoległymi slotami: @analytics, @team i @notifications. Użytkownik przechodzi do /dashboard/settings, które jest zdefiniowane w children, ale nie ma odpowiadającej podtrasy w żadnym z trzech folderów slotów.
Co dzieje się z trzema slotami i jaki plik zapobiega błędowi 404 dla całego layoutu?
Podsumowanie: warunkowe renderowanie slotów dla dashboardów i kart
W tej lekcji nauczył(a) się Pan/Pani sterować sekcjami dashboardu i widokami z kartami za pomocą Parallel Routes w Next.js 15.
Najważniejsze informacje:
- Równoległe sloty korzystają z konwencji folderów
@slotNamei są przekazywane jako propsy do nadrzędnegolayout.tsx - Plik
default.tsxw każdym folderze slotu jest wymagany do obsługi niedopasowanych adresów URL i zapobiegania błędom 404 - Layout jest Server Component, więc można uzależnić renderowanie slotów od asynchronicznego sprawdzania ról, flag funkcji lub dowolnych danych po stronie serwera
- Interfejsy z kartami mapują każdą kartę na podsegment URL w obrębie slotu, zapewniając udostępnialne, możliwe do dodania do zakładek karty renderowane na serwerze, bez narzutu stanu po stronie klienta
- Każdy slot należy umieścić we własnej granicy
<Suspense>, aby wolne sloty nie blokowały przesyłania strumieniowego szybkich slotów - Server Actions na stronach kart mogą wywoływać
revalidatePath, aby odświeżać tylko dotknięty slot, pozostawiając wszystkie pozostałe bez zmian - Miękka nawigacja za pomocą
<Link>ponownie pobiera tylko zmienione sloty i zachowuje stan Reacta w slotach, które się nie zmieniły
Parallel Routes z warunkową logiką slotów zapewniają kompozytowalną architekturę sterowaną adresem URL dla złożonych dashboardów — bez użycia choćby jednej zmiennej stanu po stronie klienta do zarządzania kartami.
Ucz się TypeScript dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 22
- Lekcje
- 88
Często zadawane pytania
Czy lekcja „Warunkowe renderowanie slotów dla pulpitów i kart” jest bezpłatna?
Tak — pełny tekst „Warunkowe renderowanie slotów dla pulpitów i kart” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Next.js 15 Fullstack (App Router + Server Actions), przejdź na CoddyKit PRO. Kurs Next.js 15 Fullstack (App Router + Server Actions) zawiera 4 lekcji w sumie.
Co nauczysz się w „Warunkowe renderowanie slotów dla pulpitów i kart”?
Steruj sekcjami pulpitu i widokami kart, mapując segmenty tras na równoległe sloty. Ćwiczysz Next.js 15 Fullstack (App Router + Server Actions) z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Next.js 15 Fullstack (App Router + Server Actions)?
Nie wymagamy żadnego doświadczenia. Next.js 15 Fullstack (App Router + Server Actions) w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Warunkowe renderowanie slotów dla pulpitów i kart”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Next.js 15 Fullstack (App Router + Server Actions)?
Tak. Każda lekcja Next.js 15 Fullstack (App Router + Server Actions) zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Równoległe trasy z nazwanymi slotami i domyślnymi segmentami
- Trasy przechwytujące dla współdzielonych widoków modalnych
- Warunkowe renderowanie slotów dla pulpitów i kart
- Budowanie przepływu modalu zdjęć z miękką nawigacją