Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Loading UI i layout.tsx

W Metropolii Quantum każdy dystrykt posiada stałą infrastrukturę — oświetlenie, systemy nawigacyjne, panele informacyjne — która pozostaje aktywna niezależnie od tego, kto aktualnie przebywa w danej strefie. Kiedy mieszkaniec przemieszcza się między sektorami, holograficzne ekrany wyświetlają animację ładowania, podczas gdy otaczająca infrastruktura pozostaje niezmieniona.

W Next.js 15 App Router te koncepcje mają swoje odpowiedniki: layout.tsx to stała infrastruktura, która otacza strony i nie jest ponownie renderowana przy nawigacji, a loading.tsx to automatyczny wskaźnik ładowania wyświetlany podczas przejść między stronami.

Czym jest layout.tsx?

Plik

layout.tsx
to jeden z najważniejszych plików specjalnych w App Router. Definiuje on współdzielony układ (shared layout), który otacza strony w danym segmencie i wszystkich jego podsegmentach. Najważniejsza cecha layoutu: nie jest ponownie renderowany przy nawigacji między stronami, które współdzielą ten sam layout. To jak infrastruktura dystryktu Quantum — pozostaje na miejscu, zmienia się tylko zawartość wewnątrz.

Root Layout — obowiązkowy layout główny

Każda aplikacja Next.js musi posiadać Root Layout w pliku

app/layout.tsx
. Jest to jedyny layout, który musi zawierać tagi
<html>
i
<body>
:

1// app/layout.tsx — Root Layout
2export default function RootLayout({
3  children,
4}: {
5  children: React.ReactNode
6}) {
7  return (
8    <html lang="pl">
9      <body>
10        <nav className="quantum-nav">
11          <a href="/">Strona główna</a>
12          <a href="/dashboard">Dashboard</a>
13          <a href="/settings">Ustawienia</a>
14        </nav>
15        <main>{children}</main>
16        <footer>Metropolis Quantum © 2150</footer>
17      </body>
18    </html>
19  );
20}

Root Layout jest renderowany raz i pozostaje aktywny przez cały czas życia aplikacji. Nawigacja między

/dashboard
a
/settings
zmieni tylko zawartość
{children}
— nawigacja i stopka pozostaną na miejscu bez ponownego renderowania.

Zagnieżdżone layouty (Nested Layouts)

Layouty można zagnieżdżać na dowolnym poziomie struktury folderów. Każdy segment ścieżki może mieć swój własny

layout.tsx
:

1app/
2  ├── layout.tsx              # Root Layout (html + body + nawigacja)
3  ├── page.tsx                # Strona główna /
4  └── dashboard/
5      ├── layout.tsx          # Dashboard Layout (sidebar + panel)
6      ├── page.tsx            # /dashboard
7      ├── analytics/
8      │   └── page.tsx        # /dashboard/analytics
9      └── settings/
10          └── page.tsx        # /dashboard/settings

Dashboard Layout zagnieżdża się wewnątrz Root Layout:

1// app/dashboard/layout.tsx — Zagnieżdżony layout
2export default function DashboardLayout({
3  children,
4}: {
5  children: React.ReactNode
6}) {
7  return (
8    <div className="dashboard-container">
9      <aside className="sidebar">
10        <h2>Panel Quantum</h2>
11        <ul>
12          <li><a href="/dashboard">Przegląd</a></li>
13          <li><a href="/dashboard/analytics">Analityka</a></li>
14          <li><a href="/dashboard/settings">Ustawienia</a></li>
15        </ul>
16      </aside>
17      <section className="content">
18        {children}
19      </section>
20    </div>
21  );
22}

Kiedy użytkownik nawiguje z

/dashboard
do
/dashboard/analytics
, Root Layout i Dashboard Layout nie są ponownie renderowane. Zmienia się tylko
{children}
w Dashboard Layout. To kluczowa optymalizacja wydajności — stan komponentów layoutu (np. otwarty sidebar, pozycja scrolla) jest zachowany.

Zachowanie stanu layoutu przy nawigacji

Jedną z największych zalet layoutów jest zachowanie stanu przy nawigacji. Wyobraź sobie panel kontrolny w Metropolii Quantum — kiedy przełączasz się między sekcjami, nie chcesz, żeby cały interfejs się przeładował:

1// app/dashboard/layout.tsx
2'use client';
3
4import { useState } from 'react';
5
6export default function DashboardLayout({
7  children,
8}: {
9  children: React.ReactNode
10}) {
11  // Ten stan PRZETRWA nawigację między /dashboard/* stronami!
12  const [sidebarOpen, setSidebarOpen] = useState(true);
13
14  return (
15    <div className="flex">
16      {sidebarOpen && (
17        <aside className="w-64 bg-gray-900 p-4">
18          <h2>Panel Quantum</h2>
19          <nav>
20            <a href="/dashboard">Przegląd</a>
21            <a href="/dashboard/analytics">Analityka</a>
22          </nav>
23        </aside>
24      )}
25      <div className="flex-1">
26        <button onClick={() => setSidebarOpen(!sidebarOpen)}>
27          {sidebarOpen ? 'Ukryj' : 'Pokaż'} sidebar
28        </button>
29        {children}
30      </div>
31    </div>
32  );
33}

Jeśli użytkownik zamknie sidebar na stronie

/dashboard
i przejdzie do
/dashboard/analytics
, sidebar pozostanie zamknięty — stan
sidebarOpen
nie jest resetowany.

loading.tsx — automatyczne stany ładowania

Plik

loading.tsx
to specjalny plik, który Next.js automatycznie wyświetla jako fallback podczas ładowania zawartości strony. To jak holograficzny ekran ładowania w Metropolii Quantum — pojawia się automatycznie, gdy system przygotowuje dane.

Jak działa loading.tsx?

1// app/dashboard/loading.tsx
2export default function DashboardLoading() {
3  return (
4    <div className="loading-screen">
5      <div className="spinner"></div>
6      <p>Ładowanie danych panelu Quantum...</p>
7    </div>
8  );
9}

Next.js automatycznie opakowuje

page.tsx
w granicę
<Suspense>
, używając
loading.tsx
jako fallback:

1// To jest to, co Next.js robi "pod maską":
2<Layout>
3  <Suspense fallback={<Loading />}>
4    <Page />
5  </Suspense>
6</Layout>

Dzięki temu:

  • Layout jest wyświetlany natychmiast (nie czeka na dane strony)
  • Komponent loading pojawia się automatycznie podczas ładowania
  • Strona zastępuje loading, gdy dane są gotowe
  • Użytkownik widzi responsywny interfejs zamiast pustego ekranu

loading.tsx na różnych poziomach

Każdy segment może mieć własny

loading.tsx
:

1app/
2  ├── loading.tsx                # Loading dla strony głównej
3  ├── dashboard/
4  │   ├── loading.tsx            # Loading dla /dashboard/*
5  │   ├── analytics/
6  │   │   └── loading.tsx        # Loading specyficzny dla analityki
7  │   └── settings/
8  │       └── page.tsx           # Użyje loading z /dashboard/

template.tsx vs layout.tsx

Next.js oferuje jeszcze jeden specjalny plik —

template.tsx
. Wygląda identycznie jak
layout.tsx
, ale ma jedną kluczową różnicę: template jest ponownie montowany (tworzona jest nowa instancja) przy każdej nawigacji.

1// app/dashboard/template.tsx
2// Nowa instancja przy KAŻDEJ nawigacji!
3export default function DashboardTemplate({
4  children,
5}: {
6  children: React.ReactNode
7}) {
8  return (
9    <div className="animate-fadeIn">
10      {children}
11    </div>
12  );
13}

Kiedy używać

template.tsx
zamiast
layout.tsx
?

| Cecha | layout.tsx | template.tsx | |-------|-----------|-------------| | Ponowne renderowanie | NIE — zachowuje stan | TAK — nowa instancja | | Stan komponentu | Zachowany między nawigacjami | Resetowany przy nawigacji | | useEffect | Nie uruchamia się ponownie | Uruchamia się przy każdej nawigacji | | Animacje wejścia | Nie powtarzają się | Powtarzają się przy każdym wejściu |

Przykłady użycia

template.tsx
:

  • Animacje wejścia/wyjścia na stronach (fade-in przy każdej nawigacji)
  • Logowanie wyświetleń strony (useEffect z analytics przy każdym wejściu)
  • Formularze, które powinny się resetować przy nawigacji

Praktyczne zastosowania

Nawigacja z aktywnym stanem

1// app/dashboard/layout.tsx
2'use client';
3
4import Link from 'next/link';
5import { usePathname } from 'next/navigation';
6
7export default function DashboardLayout({
8  children,
9}: {
10  children: React.ReactNode
11}) {
12  const pathname = usePathname();
13
14  const links = [
15    { href: '/dashboard', label: 'Przegląd' },
16    { href: '/dashboard/analytics', label: 'Analityka' },
17    { href: '/dashboard/settings', label: 'Ustawienia' },
18  ];
19
20  return (
21    <div className="dashboard">
22      <nav className="dashboard-nav">
23        {links.map((link) => (
24          <Link
25            key={link.href}
26            href={link.href}
27            className={pathname === link.href ? 'active' : ''}
28          >
29            {link.label}
30          </Link>
31        ))}
32      </nav>
33      <main>{children}</main>
34    </div>
35  );
36}

Podsumowanie

Layouty i loading UI to fundamentalne koncepcje App Router w Next.js 15:

  1. layout.tsx — współdzielony układ, który otacza strony i nie jest ponownie renderowany przy nawigacji. Zachowuje stan komponentów.
  2. Root Layout — obowiązkowy główny layout z tagami
    <html>
    i
    <body>
    .
  3. Zagnieżdżone layouty — każdy segment może mieć swój layout, tworząc hierarchię układów.
  4. loading.tsx — automatyczny wskaźnik ładowania. Next.js opakowuje stronę w
    <Suspense>
    z loading jako fallback.
  5. template.tsx — jak layout, ale tworzy nową instancję przy każdej nawigacji. Idealne do animacji i logowania.

Te mechanizmy, inspirowane stałą infrastrukturą dystryktów Metropolii Quantum, pozwalają budować wydajne i responsywne interfejsy, gdzie użytkownik nigdy nie widzi pustego ekranu, a nawigacja jest płynna i natychmiastowa.

Przejdź do CodeWorlds