Kurs Next.js · Moduł 2: Routing i layouty

Prefetching i optymalizacja nawigacji

17 min czytania ·
W tej lekcji10

W Metropolii Quantum zaawansowany system transportowy opiera się na predykcji i planowaniu wyprzedzającym. Pojazdy Q-Link, zanim pasażer wyda polecenie podróży, już analizują typowe trasy, przygotowują najszybsze połączenia i wstępnie rozgrzewają silniki do optymalnej temperatury. Ta technologia "quantum prefetching" pozwala na niemal natychmiastowe rozpoczęcie podróży po wydaniu komendy, eliminując opóźnienia i zapewniając płynne przemieszczanie się po całym mieście.

W świecie Next.js 16 podobne zasady znajdują zastosowanie w mechanizmach prefetchingu i optymalizacji nawigacji. Te techniki znacząco poprawiają doświadczenie użytkownika, minimalizują opóźnienia i maksymalizują wydajność naszych aplikacji.

Zrozumienie prefetchingu w Next.js 16

Prefetching (wstępne ładowanie) to technika, która polega na ładowaniu zasobów w tle, zanim użytkownik ich bezpośrednio zażąda. W Next.js 16 prefetching jest wbudowany w komponent Link i działa automatycznie, ale możemy też precyzyjnie kontrolować jego zachowanie.

Automatyczny prefetching

W Next.js 16 prefetching jest domyślnie włączony dla komponentu Link, ale działa tylko w wersji produkcyjnej (po next build i next start). Gdy link pojawi się w obszarze widocznym (viewport) przeglądarki, Next.js pobiera w tle dane strony docelowej: dla trasy statycznej całą stronę, a dla dynamicznej tylko część do najbliższego pliku loading.tsx (bez takiego pliku prefetch trasy dynamicznej jest pomijany). Next.js 16 przebudował ten mechanizm: wspólny layout pobiera tylko raz dla wielu linków i dociąga wyłącznie te fragmenty, których nie ma jeszcze w pamięci podręcznej.

// Automatyczny prefetching linków w obszarze widocznym
<Link href="/destinations/mars">
  Eksploruj Marsa
</Link>

Ten mechanizm działa jak system predykcji ruchu w Metropolii Quantum - gdy pojazd zbliża się do skrzyżowania, system już planuje optymalne trasy dla wszystkich możliwych kierunków.

Kontrola prefetchingu

Możemy precyzyjnie kontrolować zachowanie prefetchingu za pomocą właściwości prefetch komponentu Link:

// Wyłączenie prefetchingu dla linku
<Link href="/rarely-visited-page" prefetch={false}>
  Rzadko odwiedzana strona
</Link>

Wyłączenie prefetchingu może być przydatne dla linków, które są rzadko używane lub prowadzą do stron, które wymagają dużych zasobów. To jak wyłączenie systemu wstępnego przygotowania dla rzadko wybieranych destynacji w Metropolii Quantum, oszczędzając energię i zasoby.

Wpływ na wydajność aplikacji

Prefetching ma znaczący wpływ na wydajność aplikacji i doświadczenie użytkownika:

  1. Szybsza nawigacja - Strony ładują się niemal natychmiast, ponieważ zasoby są już wstępnie załadowane.
  2. Mniej czekania po kliknięciu - dane strony są już pobrane, gdy użytkownik kliknie; kosztem są dodatkowe żądania do serwera, także dla linków, w które nikt nie kliknie.
  3. Oszczędność zasobów - Selektywne stosowanie prefetchingu pozwala oszczędzać zasoby dla mniej istotnych linków.

Komponent Link ma też kilka usprawnień, które dodatkowo optymalizują nawigację. Część z nich jest dostępna od Next.js 13, a Next.js 16 dołożył do nich oszczędniejszy prefetching opisany wyżej.

Automatyczne przesyłanie atrybutów do tagu <a>

Od Next.js 13 komponent Link automatycznie przekazuje wszystkie atrybuty do wewnętrznego tagu <a>, co upraszcza kod i poprawia SEO:

// Next.js 13+ (także 16) - uproszczona składnia
<Link
  href="/destinations/mars"
  className="btn btn-primary"
  aria-label="Eksploruj Marsa"
  target="_blank"
  rel="noopener noreferrer"
>
  Eksploruj Marsa
</Link>

Ta automatyzacja działa jak inteligentne interfejsy pojazdów w Metropolii Quantum, które automatycznie dostosowują swoje ustawienia do preferencji pasażera bez potrzeby ręcznej konfiguracji.

Opcja scroll

Komponent Link pozwala również kontrolować zachowanie przewijania strony po nawigacji:

// Wyłączenie automatycznego przewijania do góry strony
<Link href="/destinations" scroll={false}>
  Zobacz destynacje
</Link>

Ta opcja jest szczególnie przydatna, gdy chcemy zachować pozycję przewijania, np. podczas nawigacji wewnątrz długiej listy lub gdy implementujemy niestandardowe efekty przewijania.

Linki do tras dynamicznych

Efektywne użycie parametrów dynamicznych w komponentach Link pozwala na bardziej elastyczną nawigację:

// Dynamiczne parametry w komponencie Link
const destinations = ['mars', 'europa', 'titan'];

return (
  <ul>
    {destinations.map(destination => (
      <li key={destination}>
        <Link href={`/destinations/${destination}`}>
          Eksploruj {destination.charAt(0).toUpperCase() + destination.slice(1)}
        </Link>
      </li>
    ))}
  </ul>
);

Ten wzorzec pozwala na budowanie dynamicznych menu nawigacyjnych i list, podobnie jak system dynamicznych tras w Metropolii Quantum, który pozwala na wybór dowolnej kombinacji punktów pośrednich.

W App Routerze obiekt { pathname: '/destinations/[id]', query: { id } } nie wstawia parametru do ścieżki (dałby adres /destinations/[id]?id=mars); obiekt z query służy tylko do parametrów zapytania, np. { pathname: '/search', query: { q: 'mars' } }.

Programowe ładowanie wstępne z useRouter

Oprócz deklaratywnego prefetchingu za pomocą komponentu Link, Next.js 16 umożliwia również programowe wstępne ładowanie stron za pomocą hooka useRouter.

Podstawowe użycie router.prefetch

'use client';

import { useRouter } from 'next/navigation';
import { useEffect } from 'react';

export default function DestinationCard({
  destination,
}: {
  destination: { id: string; name: string; description: string; isPopular?: boolean };
}) {
  const router = useRouter();

  // Wstępne ładowanie strony szczegółów po najechaniu myszką
  const handleHover = () => {
    router.prefetch(`/destinations/${destination.id}`);
  };

  // Wstępne ładowanie najczęściej odwiedzanych stron przy montowaniu komponentu
  useEffect(() => {
    if (destination.isPopular) {
      router.prefetch(`/destinations/${destination.id}`);
    }
  }, [destination, router]);

  return (
    <div
      className="destination-card"
      onMouseEnter={handleHover}
      onClick={() => router.push(`/destinations/${destination.id}`)}
    >
      <h3>{destination.name}</h3>
      <p>{destination.description}</p>
    </div>
  );
}

Ten wzorzec przypomina inteligentny system Metropolii Quantum, który przygotowuje pojazdy do podróży, gdy mieszkaniec zbliża się do stacji, nawet zanim podejmie ostateczną decyzję o podróży.

Strategiczne prefetchowanie

W bardziej zaawansowanych scenariuszach możemy stosować strategiczne prefetchowanie, oparte na analizie zachowań użytkownika:

'use client';

import { useRouter } from 'next/navigation';
import { useEffect } from 'react';

export default function Dashboard({ user }) {
  const router = useRouter();

  useEffect(() => {
    // Prefetchowanie stron na podstawie historii użytkownika
    if (user.mostVisitedDestinations) {
      user.mostVisitedDestinations.forEach(destination => {
        router.prefetch(`/destinations/${destination.id}`);
      });
    }

    // Prefetchowanie stron na podstawie pory dnia
    const currentHour = new Date().getHours();
    if (currentHour >= 9 && currentHour <= 17) {
      // W godzinach pracy prefetchuj biznesowe destynacje
      router.prefetch('/destinations/business');
    } else {
      // Po godzinach pracy prefetchuj rekreacyjne destynacje
      router.prefetch('/destinations/recreation');
    }

    // Prefetchowanie stron na podstawie nadchodzących wydarzeń
    if (user.upcomingTrip) {
      router.prefetch(`/trips/${user.upcomingTrip.id}`);
      router.prefetch(`/checklist/${user.upcomingTrip.id}`);
    }
  }, [user, router]);

  return (
    <div className="dashboard">
      {/* Zawartość dashboardu */}
    </div>
  );
}

Ta zaawansowana strategia prefetchingu przypomina predykcyjny system Metropolii Quantum, który analizuje wzorce ruchu i preferencje mieszkańców, aby z wyprzedzeniem przygotować pojazdy i trasy.

Optymalizacja ładowania danych

W Next.js 16 optymalizacja nawigacji jest ściśle powiązana z optymalizacją ładowania danych. App Router wprowadza nowe metody efektywnego pozyskiwania i buforowania danych.

Ładowanie danych w Server Components

Server Components w Next.js 16 pozwalają na ładowanie danych bezpośrednio w komponencie, bez konieczności używania dodatkowych API:

// app/destinations/[id]/page.tsx
export default async function DestinationPage({ params }: { params: Promise<{ id: string }> }) {
  // Ładowanie danych bezpośrednio w komponencie
  const destination = await fetchDestination((await params).id);

  return (
    <div className="destination-page">
      <h1>{destination.name}</h1>
      <p>{destination.description}</p>
      {/* Więcej treści */}
    </div>
  );
}

Ta metoda eliminuje dodatkowe żądania API, które są typowe dla tradycyjnych aplikacji React. Jest to podobne do zintegrowanego systemu Metropolii Quantum, który łączy planowanie trasy i sterowanie pojazdem w jednym procesie, eliminując potrzebę komunikacji między różnymi systemami.

Równoległe ładowanie danych

Możemy optymalizować ładowanie danych poprzez równoległe wykonywanie zapytań:

// app/destinations/[id]/page.tsx
export default async function DestinationPage({ params }: { params: Promise<{ id: string }> }) {
  // Równoległe ładowanie danych
  const [destination, attractions, reviews] = await Promise.all([
    fetchDestination((await params).id),
    fetchAttractions((await params).id),
    fetchReviews((await params).id)
  ]);

  return (
    <div className="destination-page">
      <h1>{destination.name}</h1>
      <section className="attractions">
        <h2>Popularne atrakcje</h2>
        <AttractionsList attractions={attractions} />
      </section>
      <section className="reviews">
        <h2>Opinie podróżnych</h2>
        <ReviewsList reviews={reviews} />
      </section>
    </div>
  );
}

Ta technika przypomina system transportowy Metropolii Quantum, który równolegle przygotowuje różne elementy podróży - pojazd, trasę i punkty pośrednie - aby skrócić całkowity czas przygotowania.

Wykorzystanie generateMetadata i generateStaticParams

Next.js 16 dostarcza specjalne funkcje do optymalizacji danych dla metadanych i statycznych parametrów:

// app/destinations/[id]/page.tsx
import type { Metadata } from 'next';

// Funkcja generująca metadane strony
export async function generateMetadata(
  { params }: { params: Promise<{ id: string }> }
): Promise<Metadata> {
  // Pobranie danych tylko dla metadanych
  const destination = await fetchDestinationBasic((await params).id);

  return {
    title: `${destination.name} - Quantum Voyages`,
    description: destination.shortDescription,
    openGraph: {
      images: [{ url: destination.imageUrl }],
    },
  };
}

// Funkcja generująca statyczne parametry dla popularnych destynacji
export async function generateStaticParams() {
  // Pobranie tylko najpopularniejszych destynacji dla prerendering
  const popularDestinations = await fetchPopularDestinations();

  return popularDestinations.map((destination) => ({
    id: destination.id,
  }));
}

export default async function DestinationPage({ params }: { params: Promise<{ id: string }> }) {
  // Pobieranie pełnych danych dla strony
  const destination = await fetchDestinationFull((await params).id);

  return (
    <div className="destination-page">
      {/* Zawartość strony */}
    </div>
  );
}

Te specjalne funkcje pozwalają na selektywne ładowanie danych dla różnych aspektów strony, podobnie jak system Metropolii Quantum, który przydziela zasoby dla różnych aspektów podróży na podstawie ich priorytetów.

Strategie buforowania danych

Next.js 16 oferuje elastyczne strategie buforowania danych, które można dostosować do specyficznych potrzeb każdej aplikacji. Poniższe opcje fetch należą do domyślnego modelu cachowania Next.js 16 (bez włączonego cacheComponents). Pamiętaj, że od Next.js 15 zapytania fetch nie są domyślnie buforowane, więc buforowanie włączasz jawnie.

Buforowanie statyczne i dynamiczne

// app/destinations/page.tsx
export default async function DestinationsPage() {
  // Dane, które rzadko się zmieniają - buforowanie statyczne
  const categories = await fetchCategories({
    next: { revalidate: 3600 } // Odświeżanie co godzinę
  });

  // Dane, które często się zmieniają - buforowanie dynamiczne
  const featuredDestinations = await fetchFeaturedDestinations({
    next: { revalidate: 60 } // Odświeżanie co minutę
  });

  // Dane unikalne dla każdego żądania - bez buforowania
  const userRecommendations = await fetchUserRecommendations({
    cache: 'no-store'
  });

  return (
    <div className="destinations-page">
      <CategoriesList categories={categories} />
      <FeaturedDestinations destinations={featuredDestinations} />
      <RecommendationsList recommendations={userRecommendations} />
    </div>
  );
}

Ta elastyczna strategia buforowania przypomina system transportowy Metropolii Quantum, który przechowuje w pamięci podręcznej różne rodzaje informacji z różnymi cyklami odświeżania - trwałe informacje o punktach orientacyjnych są buforowane na dłużej, podczas gdy dynamiczne informacje o ruchu są aktualizowane częściej.

Rewalidacja na żądanie

Next.js 16 umożliwia również rewalidację buforowanych danych na żądanie, co jest przydatne po aktualizacji danych. Zwróć uwagę na drugi argument revalidateTag: od Next.js 16 to profil cacheLife, a zalecana wartość 'max' oznacza, że użytkownik dostaje starą wersję, a świeża ładuje się w tle. Wersja z jednym argumentem jest przestarzała:

// app/api/revalidate/route.ts
import { NextRequest } from 'next/server';
import { revalidatePath, revalidateTag } from 'next/cache';

export async function GET(request: NextRequest) {
  const tag = request.nextUrl.searchParams.get('tag');
  const path = request.nextUrl.searchParams.get('path');

  if (tag) {
    revalidateTag(tag, 'max');
    return Response.json({ revalidated: true, tag });
  }

  if (path) {
    revalidatePath(path);
    return Response.json({ revalidated: true, path });
  }

  return Response.json({ revalidated: false, message: 'No tag or path provided' }, { status: 400 });
}

Ta funkcjonalność działa jak system aktualizacji tras w Metropolii Quantum, który może natychmiast rozpowszechniać informacje o zmianach w infrastrukturze miasta do wszystkich pojazdów, bez czekania na regularne cykle aktualizacji.

Optymalizacja renderowania komponentów

Optymalizacja nawigacji w Next.js 16 obejmuje również optymalizację renderowania komponentów.

Streaming i Suspense

Next.js 16 obsługuje streaming i Suspense, które pozwalają na stopniowe renderowanie interfejsu użytkownika:

// app/destinations/[id]/page.tsx
import { Suspense } from 'react';
import DestinationHeader from './DestinationHeader';
import AttractionsList from './AttractionsList';
import WeatherWidget from './WeatherWidget';
import ReviewsList from './ReviewsList';
import RelatedDestinations from './RelatedDestinations';

export default async function DestinationPage({ params }: { params: Promise<{ id: string }> }) {
  // Pobieranie podstawowych informacji potrzebnych od razu
  const destinationInfo = await fetchDestinationInfo((await params).id);

  return (
    <div className="destination-page">
      <DestinationHeader info={destinationInfo} />

      <div className="destination-content grid grid-cols-1 lg:grid-cols-3 gap-6">
        <div className="lg:col-span-2">
          {/* Komponent, który może się wolno ładować */}
          <Suspense fallback={<div className="attractions-loading">Ładowanie atrakcji...</div>}>
            <AttractionsList destinationId={(await params).id} />
          </Suspense>

          {/* Kolejny komponent z potencjalnie długim czasem ładowania */}
          <Suspense fallback={<div className="reviews-loading">Ładowanie opinii...</div>}>
            <ReviewsList destinationId={(await params).id} />
          </Suspense>
        </div>

        <div className="lg:col-span-1">
          {/* Komponenty w prawej kolumnie */}
          <Suspense fallback={<div className="weather-loading">Ładowanie pogody...</div>}>
            <WeatherWidget destinationId={(await params).id} />
          </Suspense>

          <Suspense fallback={<div className="related-loading">Ładowanie powiązanych destynacji...</div>}>
            <RelatedDestinations currentId={(await params).id} />
          </Suspense>
        </div>
      </div>
    </div>
  );
}

Ta technika przypomina system transportowy Metropolii Quantum, który pozwala pasażerom wsiadać do pojazdu i rozpoczynać podróż, nawet jeśli niektóre systemy pokładowe (np. rozrywka czy informacje o trasie) są jeszcze w trakcie ładowania.

Selektywne renderowanie z Client i Server Components

Właściwe rozdzielenie komponentów na Server Components i Client Components może znacząco poprawić wydajność:

// app/destinations/[id]/page.tsx - Server Component
import { fetchDestination } from '@/lib/data';
import DestinationDetails from './DestinationDetails';
import InteractiveMap from './InteractiveMap'; // Client Component
import TripPlanner from './TripPlanner'; // Client Component

export default async function DestinationPage({ params }: { params: Promise<{ id: string }> }) {
  // Ładowanie danych na serwerze
  const destination = await fetchDestination((await params).id);

  return (
    <div className="destination-page">
      {/* Server Component - renderowany na serwerze */}
      <DestinationDetails destination={destination} />

      {/* Client Components - renderowane interaktywnie po stronie klienta */}
      <div className="interactive-components mt-8 flex flex-col lg:flex-row gap-6">
        <InteractiveMap
          coordinates={destination.coordinates}
          points={destination.interestPoints}
        />

        <TripPlanner
          destinationId={destination.id}
          initialDates={destination.availableDates}
        />
      </div>
    </div>
  );
}

Ta hybrydowa strategia renderowania działa jak zoptymalizowany system Metropolii Quantum, który łączy elementy scentralizowanego planowania (Server Components) z autonomicznym zachowaniem pojazdów (Client Components), aby zoptymalizować całe doświadczenie.

Optymalizacja obrazów i zasobów statycznych

Optymalizacja zasobów statycznych jest kluczowa dla szybkiej nawigacji w aplikacji Next.js 16.

Komponent Image

Next.js 16 dostarcza komponent Image, który automatycznie optymalizuje obrazy:

// app/destinations/[id]/page.tsx
import Image from 'next/image';

export default async function DestinationPage({ params }: { params: Promise<{ id: string }> }) {
  const destination = await fetchDestination((await params).id);

  return (
    <div className="destination-page">
      <div className="destination-hero relative h-96 mb-8">
        <Image
          src={destination.imageUrl}
          alt={destination.name}
          fill
          sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
          preload={true} // Ładowanie z wysokim priorytetem
          className="object-cover rounded-lg"
        />
      </div>

      <h1 className="text-4xl font-bold mb-4">{destination.name}</h1>
      <p className="text-lg mb-8">{destination.description}</p>

      <div className="attractions grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
        {destination.attractions.map(attraction => (
          <div key={attraction.id} className="attraction-card relative h-64">
            <Image
              src={attraction.imageUrl}
              alt={attraction.name}
              fill
              sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
              className="object-cover rounded-lg"
            />
            <div className="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent rounded-lg">
              <div className="absolute bottom-0 p-4 text-white">
                <h3 className="text-xl font-semibold">{attraction.name}</h3>
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Komponent Image automatycznie optymalizuje obrazy, dostosowując ich rozmiar, format i ładowanie do kontekstu wyświetlania, podobnie jak system wizualny Metropolii Quantum, który dynamicznie dostosowuje informacje wizualne do urządzenia i preferencji użytkownika.

Atrybut preload (dawniej priority)

Atrybut preload w komponencie Image pozwala na ustalenie priorytetów ładowania obrazów. W Next.js 16 zastąpił on przestarzały atrybut priority i działa tak samo: dodaje do <head> znacznik <link rel="preload">, więc obraz zaczyna się pobierać od razu. Używaj go tylko dla jednego, najważniejszego obrazu (LCP); w pozostałych przypadkach dokumentacja poleca loading="eager" albo fetchPriority="high":

// Obraz krytyczny dla LCP (Largest Contentful Paint)
<Image
  src="/hero-image.jpg"
  alt="Odkryj kosmos z Quantum Voyages"
  width={1200}
  height={600}
  preload={true}
/>

Ta funkcja działa jak system priorytetów w Metropolii Quantum, który kieruje więcej zasobów do najważniejszych aspektów podróży, zapewniając optymalną dystrybucję mocy i przepustowości.

Statyczne importy obrazów

Next.js 16 umożliwia również statyczne importowanie obrazów, co pozwala na automatyczną optymalizację i typowanie:

// Statyczny import obrazu
import marsImage from '@/public/images/destinations/mars.jpg';

export default function MarsCard() {
  return (
    <div className="destination-card">
      <Image
        src={marsImage}
        alt="Mars - czerwona planeta"
      />
      <h3>Mars</h3>
      <p>Czerwona planeta z potencjałem dla przyszłych kolonii.</p>
    </div>
  );
}

Ta technika przypomina system identyfikacji wizualnej Metropolii Quantum, który przechowuje preoptymalizowane obrazy dla wszystkich standardowych komponentów miasta, zapewniając spójną i wydajną prezentację.

Zaawansowane strategie prefetchingu

Zaawansowane zastosowania prefetchingu mogą znacząco poprawić wydajność aplikacji.

Warunkowe prefetchowanie na podstawie interakcji użytkownika

'use client';

import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';

export default function DestinationCard({
  destination,
}: {
  destination: { id: string; name: string; description: string; isPopular?: boolean };
}) {
  const router = useRouter();
  const [interactionCount, setInteractionCount] = useState(0);
  const [interactionTime, setInteractionTime] = useState(0);

  // Śledzenie interakcji użytkownika
  const trackInteraction = () => {
    setInteractionCount(prev => prev + 1);
    setInteractionTime(prev => prev + 0.5); // Symulacja czasu spędzonego nad kartą
  };

  useEffect(() => {
    // Prefetch tylko jeśli użytkownik wykazuje wystarczające zainteresowanie
    if (interactionCount > 2 || interactionTime > 1.5) {
      router.prefetch(`/destinations/${destination.id}`);
    }
  }, [interactionCount, interactionTime, destination.id, router]);

  return (
    <div
      className="destination-card"
      onMouseEnter={trackInteraction}
      onMouseMove={trackInteraction}
      onClick={() => router.push(`/destinations/${destination.id}`)}
    >
      <h3>{destination.name}</h3>
      <p>{destination.description}</p>
    </div>
  );
}

Ta zaawansowana strategia działa jak adaptacyjny system predykcji Metropolii Quantum, który analizuje poziom zainteresowania mieszkańca określonym kierunkiem i odpowiednio dostosowuje przygotowania.

Prefetching na podstawie wzorców nawigacji

Możemy analizować typowe wzorce nawigacji użytkowników i prefetchować strony, które prawdopodobnie odwiedzą:

'use client';

import { useEffect } from 'react';
import { useRouter, usePathname } from 'next/navigation';

export default function NavigationAnalytics() {
  const router = useRouter();
  const pathname = usePathname();

  useEffect(() => {
    // Określenie następnych prawdopodobnych ścieżek na podstawie aktualnej ścieżki
    const predictNextPages = (currentPath) => {
      // Wzorce nawigacji określone na podstawie analityki użytkowników
      const navigationPatterns = {
        '/destinations': ['/destinations/mars', '/destinations/europa', '/booking'],
        '/destinations/mars': ['/booking/mars', '/destinations/europa', '/destinations'],
        '/booking': ['/checkout', '/destinations', '/account'],
        '/checkout': ['/confirmation', '/dashboard', '/account'],
      };

      return navigationPatterns[currentPath] || [];
    };

    // Prefetchowanie przewidywanych ścieżek
    const nextProbablePaths = predictNextPages(pathname);
    nextProbablePaths.forEach(path => {
      router.prefetch(path);
    });
  }, [pathname, router]);

  // Ten komponent nie renderuje nic, tylko analizuje nawigację
  return null;
}

Ten system przypomina zaawansowaną predykcję tras w Metropolii Quantum, która analizuje typowe wzorce podróży mieszkańców i przygotowuje trasy, które najprawdopodobniej wybiorą, na podstawie historycznych danych i kontekstu.

Monitorowanie i optymalizacja Web Vitals

Monitorowanie wskaźników Web Vitals jest kluczowe dla optymalizacji nawigacji i ogólnego doświadczenia użytkownika.

Śledzenie Web Vitals

Next.js 16 oferuje wbudowane narzędzia do śledzenia Web Vitals:

// app/_components/web-vitals.tsx
'use client';

import { useReportWebVitals } from 'next/web-vitals';

export function WebVitalsReporter() {
  useReportWebVitals((metric) => {
    // Wysyłanie metryk do systemu analitycznego
    console.log(metric);
  });

  return null;
}

Root layout zostaje Server Componentem i tylko renderuje ten komponent, bo hooki takie jak useReportWebVitals działają wyłącznie w Client Component:

// app/layout.tsx (Server Component)
import { WebVitalsReporter } from './_components/web-vitals';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="pl">
      <body>
        <WebVitalsReporter />
        {children}
      </body>
    </html>
  );
}

Ta funkcjonalność działa jak system monitoringu Metropolii Quantum, który śledzi wszystkie aspekty podróży, od czasu oczekiwania na pojazd po płynność jazdy, aby ciągle optymalizować doświadczenie mieszkańców.

Optymalizacja Largest Contentful Paint (LCP)

Optymalizacja LCP jest kluczowa dla poprawy postrzegania szybkości ładowania:

// app/page.tsx
import Image from 'next/image';
import heroImage from '@/public/images/hero.jpg';

export default function HomePage() {
  return (
    <div className="home-page">
      {/* Optymalizacja LCP poprzez priorytetowe ładowanie głównego obrazu */}
      <div className="hero-section relative h-[80vh]">
        <Image
          src={heroImage}
          alt="Quantum Voyages - Twoja brama do kosmosu"
          fill
          preload={true} // Ważne dla LCP
          className="object-cover"
        />
        <div className="absolute inset-0 flex items-center justify-center">
          <div className="text-center text-white">
            <h1 className="text-5xl font-bold mb-4">Odkryj kosmos z Quantum Voyages</h1>
            <p className="text-xl mb-8">Twoja brama do międzyplanetarnych podróży</p>
            <button className="bg-indigo-600 hover:bg-indigo-700 text-white py-3 px-8 rounded-full">
              Rozpocznij podróż
            </button>
          </div>
        </div>
      </div>

      {/* Pozostała treść strony */}
    </div>
  );
}

Ta technika optymalizacji działa jak system pierwszego wrażenia w Metropolii Quantum, który zapewnia, że najważniejsze elementy doświadczenia podróży są dostarczane w pierwszej kolejności, tworząc pozytywne pierwsze wrażenie.

Minimalizacja Cumulative Layout Shift (CLS)

Zmniejszenie przesunięć układu jest kluczowe dla płynnego doświadczenia:

// app/destinations/[id]/page.tsx
import Image from 'next/image';

export default async function DestinationPage({ params }: { params: Promise<{ id: string }> }) {
  const destination = await fetchDestination((await params).id);

  return (
    <div className="destination-page">
      {/* Zapobieganie CLS przez określenie wymiarów obrazu */}
      <div className="destination-hero relative aspect-[16/9] mb-8">
        <Image
          src={destination.imageUrl}
          alt={destination.name}
          fill
          sizes="100vw"
          className="object-cover rounded-lg"
        />
      </div>

      {/* Zapobieganie CLS przez rezerwację przestrzeni dla dynamicznej zawartości */}
      <div className="content-container min-h-[500px]">
        <h1 className="text-4xl font-bold mb-4">{destination.name}</h1>
        <p className="text-lg mb-8">{destination.description}</p>

        {/* Więcej treści */}
      </div>
    </div>
  );
}

Ta technika przypomina system stabilizacji Metropolii Quantum, który zapewnia, że elementy miasta nie przesuwają się w nieoczekiwany sposób, nawet gdy nowe informacje lub usługi są dodawane w czasie rzeczywistym.

Podsumowanie

Prefetching i optymalizacja nawigacji w Next.js 16 to potężne narzędzia, które znacząco poprawiają doświadczenie użytkownika i wydajność aplikacji. Podobnie jak zaawansowany system transportowy Metropolii Quantum, który wykorzystuje technologię "quantum prefetching" do eliminacji opóźnień, Next.js 16 oferuje szereg funkcji i strategii, które umożliwiają tworzenie niezwykle responsywnych i wydajnych aplikacji:

  1. Automatyczny prefetching - komponent Link automatycznie ładuje zasoby w tle, gdy link pojawia się w obszarze widocznym.

  2. Programowe prefetchowanie - hook useRouter pozwala na strategiczne wstępne ładowanie stron na podstawie interakcji użytkownika, wzorców nawigacji i innych czynników.

  3. Optymalizacja ładowania danych - Server Components, równoległe zapytania i elastyczne strategie buforowania minimalizują opóźnienia związane z pobieraniem danych.

  4. Selektywne renderowanie - właściwe wykorzystanie Server i Client Components pozwala na optymalne rozdzielenie logiki renderowania.

  5. Streaming i Suspense - stopniowe renderowanie interfejsu użytkownika zapewnia responsywne doświadczenie nawet podczas ładowania wolniejszych elementów.

  6. Optymalizacja zasobów statycznych - komponent Image i inne narzędzia automatycznie optymalizują obrazy i inne zasoby.

  7. Monitorowanie i optymalizacja Web Vitals - narzędzia do śledzenia i poprawy kluczowych wskaźników wydajności.

Dzięki zastosowaniu tych technik nasza aplikacja Quantum Voyages może oferować niemal natychmiastową nawigację i płynne doświadczenie, podobnie jak zaawansowany system transportowy Metropolii Quantum, który eliminuje opóźnienia i zapewnia płynne przemieszczanie się po całym mieście.

W następnej lekcji zobaczysz, jak zmieniać adres URL bez przeładowania strony (shallow routing).

Hasła z dokumentacji w tej lekcji

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Jak wyłączyć automatyczny prefetching dla pojedynczego komponentu Link?

  2. 2. Której metody hooka useRouter używa się do programowego wstępnego ładowania strony (np. po najechaniu myszką)?

Zadania praktyczne w grze

  • Układanie w poziomie

    Ułóż składnię otwarcia komponentu Link wyłączającego automatyczne przewijanie do góry strony

Przydatne artykuły