Kurs Next.js · Moduł 2: Routing i layouty
Prefetching i optymalizacja nawigacji
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:
- Szybsza nawigacja - Strony ładują się niemal natychmiast, ponieważ zasoby są już wstępnie załadowane.
- 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.
- Oszczędność zasobów - Selektywne stosowanie prefetchingu pozwala oszczędzać zasoby dla mniej istotnych linków.
Optymalizacja komponentu Link
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:
Automatyczny prefetching - komponent
Linkautomatycznie ładuje zasoby w tle, gdy link pojawia się w obszarze widocznym.Programowe prefetchowanie - hook
useRouterpozwala na strategiczne wstępne ładowanie stron na podstawie interakcji użytkownika, wzorców nawigacji i innych czynników.Optymalizacja ładowania danych - Server Components, równoległe zapytania i elastyczne strategie buforowania minimalizują opóźnienia związane z pobieraniem danych.
Selektywne renderowanie - właściwe wykorzystanie Server i Client Components pozwala na optymalne rozdzielenie logiki renderowania.
Streaming i Suspense - stopniowe renderowanie interfejsu użytkownika zapewnia responsywne doświadczenie nawet podczas ładowania wolniejszych elementów.
Optymalizacja zasobów statycznych - komponent
Imagei inne narzędzia automatycznie optymalizują obrazy i inne zasoby.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. Jak wyłączyć automatyczny prefetching dla pojedynczego komponentu Link?
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