Renderowanie w Next.js - server i client components w pigułce

Blog image - Renderowanie w Next.js - server i client components w pigułce

16/12/2023

8 min

Bartosz Lewandowski

Renderowanie w Next.js - server i client components w pigułce

16/12/2023

8 min

Bartosz Lewandowski

Blog image - Renderowanie w Next.js - server i client components w pigułce

Spis Treści

  1. Renderowanie - z czym to się je?
  2. Server Components
  3. Client Components
  4. Przykładowa struktura aplikacji
  5. Suspense i Streaming
  6. Podsumowanie

Dzięki wpisowi Routing w Next.js - na czym polega i jak tworzyć routy odkryłeś już tajemnice routingu w Next.js, ale czy jesteś gotowy na kolejny poziom? Przygotuj się na ekscytującą podróż po świecie renderowania w Next.js! Poznaj magię Server Components, baw się możliwościami Client Components i odkryj, jak Suspense oraz Streaming rewolucjonizują wydajność i interaktywność Twojej aplikacji. Czy jesteś gotowy do odkrycia, jak ożywić Twoją aplikację jak nigdy dotąd? Czytaj dalej i zanurz się w nowe wymiary Next.js!

Renderowanie - z czym to się je?

Renderowanie w kontekście aplikacji webowych odnosi się do procesu przekształcania kodu, który piszesz, w interfejsy użytkownika. Next.js umożliwia tworzenie hybrydowych aplikacji webowych, w których część kodu może być renderowana na serwerze, a część na kliencie. W tej sekcji zostanie wyjaśnione, na czym polegają różnice między tymi środowiskami renderowania, strategiami oraz runtime'ami.Klient odnosi się do przeglądarki na urządzeniu użytkownika, która wysyła żądanie do serwera o kod aplikacji, a następnie przekształca odpowiedź serwera w interfejs użytkownika. Serwer to komputer, który przechowuje kod aplikacji, otrzymuje żądania od klienta i wysyła odpowiednią odpowiedź.

Cykl życia żądania i odpowiedzi w aplikacjach internetowych

W każdej aplikacji internetowej, niezależnie od jej rodzaju, występuje pewien standardowy cykl działań, który można opisać w kilku krokach:

  1. Interakcja użytkownika: Wszystko zaczyna się od akcji użytkownika. Może to być na przykład kliknięcie w link, wypełnienie i wysłanie formularza, lub wprowadzenie adresu strony bezpośrednio w pasku adresu przeglądarki.
  2. Wysyłanie żądania HTTP: W odpowiedzi na działanie użytkownika, przeglądarka (klient) wysyła żądanie do serwera. W tym żądaniu znajdują się informacje o tym, czego użytkownik potrzebuje - mogą to być określone strony, obrazy, skrypty itp., a także informacje o sposobie żądania (np. metodzie GET lub POST) i ewentualne dodatkowe dane.
  3. Przetwarzanie żądania przez serwer: Kiedy serwer otrzyma żądanie, rozpoczyna proces jego przetwarzania. Może to obejmować różne działania, jak na przykład przekierowanie żądania do odpowiedniego miejsca (routing), pobieranie danych z bazy danych lub wykonanie obliczeń serwerowych.
  4. Odpowiedź serwera: Po przetworzeniu żądania, serwer odpowiada, wysyłając z powrotem do klienta odpowiedź HTTP. Zawiera ona kod statusu, który informuje, czy żądanie zostało przetworzone pomyślnie, oraz żądane zasoby, takie jak kod HTML, CSS, JavaScript, czy też inne pliki.
  5. Przetwarzanie odpowiedzi przez klienta: Klient, czyli zazwyczaj przeglądarka internetowa, odbiera odpowiedź i na jej podstawie renderuje interfejs użytkownika - to znaczy przekształca otrzymane dane w widoczne dla użytkownika elementy strony.
  6. Dalsza interakcja użytkownika: Gdy strona jest już wyrenderowana, użytkownik może z nią wchodzić w dalsze interakcje, co może prowadzić do kolejnych żądań i odpowiedzi, i tak cykl się powtarza.

Podczas budowania hybrydowych aplikacji internetowych, bardzo ważnym aspektem jest decyzja o tym, jak podzielić pracę pomiędzy serwerem a klientem w tym cyklu, oraz gdzie dokładnie ustawić granicę między tymi dwoma środowiskami. To właśnie ta granica decyduje o tym, jakie części aplikacji są przetwarzane po stronie serwera, a jakie po stronie klienta.

Server Components

Server Components w Next.js to technologia umożliwiająca tworzenie interfejsów użytkownika, które są renderowane na serwerze. W Next.js proces renderowania jest rozdzielany zgodnie z segmentami tras, co umożliwia strumieniowe przesyłanie danych oraz częściowe renderowanie. Istnieją trzy główne strategie renderowania na serwerze:

  1. Statyczne renderowanie: Ta metoda polega na renderowaniu tras podczas budowy aplikacji lub w tle po aktualizacji danych. Wynik ten może być rozpowszechniany za pomocą sieci dostarczania treści (CDN), co pozwala na współdzielenie rezultatów renderowania między różnymi użytkownikami i żądaniami do serwera.
  2. Dynamiczne renderowanie: W tej strategii, trasy są renderowane indywidualnie dla każdego użytkownika w momencie otrzymania żądania.
  3. Strumieniowanie: Server Components pozwalają na podział pracy renderowania na części, które są następnie strumieniowo przesyłane do klienta. Umożliwia to użytkownikowi zobaczenie części strony szybciej, zanim cała zawartość zostanie wyrenderowana na serwerze.

Korzyści z renderowania na serwerze

  1. Pobieranie Danych: Server Components umożliwiają przeniesienie procesu pobierania danych na serwer, co może skrócić czas potrzebny na uzyskanie danych niezbędnych do renderowania i zmniejszyć ilość żądań wysyłanych przez klienta.
  2. Bezpieczeństwo: Dzięki Server Components można utrzymywać wrażliwe dane i logikę na serwerze, jak na przykład tokeny i klucze API, bez ryzyka ich ujawnienia klientom.
  3. Zmniejszenie rozmiaru pakietów: Server Components umożliwiają zachowanie dużych zależności, które wcześniej wpływały na rozmiar pakietu JavaScript po stronie klienta, na serwerze.
  4. Initial Page Load i First Contentful Paint (FCP): Na serwerze można wygenerować HTML, co pozwala użytkownikowi na szybki podgląd strony, bez konieczności oczekiwania na pobranie, analizę i wykonanie JavaScriptu potrzebnego do wyrenderowania strony.
  5. Server Components umożliwiają wygodne i intuicyjne pobieranie danych z różnych źródeł. Mogą one być używane jako asynchroniczne funkcje z użyciem await, co pozwala na oczekiwanie na dane. Co ciekawe, komponenty te umożliwiają bezpośrednie połączenie z bazą danych i pobranie z niej danych bezpośrednio w komponencie. Poniżej znajdziesz przykład prawidłowego użycia Server Component, który pobiera dane z bazy danych:
async function ProductsList() {
	const response = await fetch("<http://example.com/api/products>");
	const products = await response.json();
	return (
		<ul>
 
			{products.map((product) => (
				<li key={product.id}>{product.name}</li>
			))}
 
		</ul>
	);
}

Client Components

Client Components w Next.js pozwalają na tworzenie interaktywnych interfejsów użytkownika, które są renderowane po stronie klienta w momencie żądania. W Next.js korzystanie z renderowania po stronie klienta (client-side rendering) jest opcją do wyboru, co oznacza, że musisz wyraźnie zdecydować, które komponenty React mają być renderowane po stronie klienta. W Client Components możemy używać hooków takich jak np. useState, useEffect, useReducer, dodatkowo możemy obsługiwać zdarzenia np. onClick Poniżej znajdziesz informacje o tym, jak działają Client Components, jak są renderowane i kiedy możesz ich używać.

Użycie

Aby używać Client Components, możesz dodać "use client" na początku pliku, powyżej importów."use client" jest używane do deklarowania granicy między modułami Server i Client Components. Oznacza to, że definiując "use client" w pliku, wszystkie inne moduły importowane do tego pliku, w tym komponenty podrzędne, są traktowane jako część pakietu klienta. Przykład:

import { useState } from "react";
 
export default function Counter() {
	const [count, setCount] = useState(0);
	return (
		<div>
			      <p>You clicked {count} times</p>      
			<button onClick={() => setCount(count + 1)}>Click me</button>    
		</div>
	);
}

Korzyści z renderowania po stronie klienta

Renderowanie po stronie klienta oferuje kilka korzyści, w tym:

  • Interaktywność: Client Components mogą używać stanu, efektów i nasłuchiwania zdarzeń, co oznacza, że mogą zapewniać natychmiastowy feedback dla użytkownika i aktualizować UI.
  • API przeglądarki: Client Components mają dostęp do API przeglądarki, takich jak geolokalizacja czy localStorage, co pozwala tworzyć interfejs użytkownika dostosowany do konkretnych przypadków użycia.

Przykładowa struktura aplikacji

Załóżmy, że budujemy aplikację e-commerce. Oto jak mogłaby wyglądać struktura:

Server Components:

Nawigacja: Komponenty nawigacyjne, takie jak menu główne czy linki do poszczególnych sekcji, są idealne do renderowania po stronie serwera. Lista produktów: Renderowanie listy produktów, możliwe z użyciem Server Side Rendering (SSR) dla lepszej wydajności i SEO. Szczegóły produktu: Podobnie jak lista produktów, szczegóły produktu mogą być serwowane z serwera dla szybkiego ładowania.

Client Components:

Koszyk: Dynamiczna interakcja z użytkownikiem, aktualizacje w czasie rzeczywistym. Slider: Pokazanie listy najpopularniejszych produktów wraz z animacja przewijania. Interaktywne elementy UI: Takie jak przyciski do sortowania, filtry, animacje.

Połączenie obu typów

W idealnym przypadku, obie te technologie współpracują ze sobą. Na przykład, strona szczegółów produktu (Server Component) może ładować się szybko z serwera, a następnie dynamiczne elementy, takie jak recenzje użytkowników czy formularz do dodawania opinii (Client Components), mogą być załadowane i stawać się interaktywne, gdy użytkownik przewinie do odpowiedniej sekcji strony.Pamiętaj, że wybór między Server a Client Components powinien być podyktowany potrzebami użytkownika końcowego i specyfiką danej części aplikacji, zawsze z naciskiem na wydajność i optymalizację użytkownika.

Suspense i Streaming

Płynność ładowania stron internetowych to kluczowe elementy zapewniające doskonałe doświadczenia użytkowników. Suspense, w połączeniu z technikami Streaming i Loading UI, otwiera nowe horyzonty w projektowaniu responsywnych i interaktywnych interfejsów użytkownika.

Loading UI

Zastosowanie loading.ts pozwala na tworzenie intuicyjnych i angażujących interfejsów ładowania. Zamiast tradycyjnego czekania na załadowanie całej zawartości, użytkownicy mogą natychmiast zobaczyć, że coś się wczytuje. Plik ten możemy umieścić w głównym katalogu app, bądź przy każdym page.tsx jeżeli chcemy pokazać np. inny komponent ładowania w zależności od strony.

Przykład:

export default function Loading() {
	return <div>Loading...</div>;
}

Użycie Suspense i Streaming

Wprowadzenie nowych technologii, takich jak Streaming i Suspense w React 18, znacząco wpływa na sposób, w jaki aplikacje internetowe są ładowane i renderowane. Tradycyjnie, proces ten obejmował pobieranie wszystkich danych na serwerze, renderowanie całego HTML-a, przesyłanie go na klienta i ostatecznie wyświetlanie. Te etapy były wykonywane sekwencyjnie, co oznaczało, że cała aplikacja musiała czekać, aż wszystkie jej komponenty będą gotowe do wyświetlenia.

Wprowadzenie Streamingu w React 18 znacząco zmienia ten proces. Dzięki streamingowi, ładowanie aplikacji może zostać podzielone na mniejsze, równoległe kroki. Pozwala to na wcześniejsze wyświetlanie części aplikacji, jeszcze zanim wszystkie komponenty zostaną załadowane. Nie muszą one już czekać na załadowanie i renderowanie pozostałych elementów. To przyspiesza czas ładowania strony i poprawia ogólne wrażenia użytkownika.

Kluczowym elementem wykorzystania Streamingu jest komponent <Suspense>. Umożliwia on opóźnienie renderowania części komponentów, aż ich zawartość zostanie załadowana. Dzięki temu, części aplikacji mogą być wyświetlane niezależnie od stanu załadowania innych, co jest ogromnym ułatwieniem i poprawą w stosunku do poprzednich metod.

Aby zaimplementować tę technologię, wystarczy otoczyć odpowiednie komponenty tagiem <Suspense>. Poniżej przedstawiam przykład, jak można zmodyfikować kod, aby skorzystać z zalet Streamingu i Suspense:

Przykład:

import { Suspense } from "react";
import { ProductImages, ProductDetails } from "./Components";
 
export default function Products() {
	return (
		<section>
			<Suspense fallback={<p>Loading product images...</p>}>     
				<ProductImages />    
			</Suspense>  
			<Suspense fallback={<p>Loading product details...</p>}>        
				<ProductDetails />     
			</Suspense
		</section>
	);
}

Podsumowanie

Podsumowując, w tym poście przedstawione zostały kluczowe elementy renderowania w Next.js, począwszy od różnic między renderowaniem na serwerze i na kliencie, poprzez szczegółowe omówienie Server Components oraz Client Components, a kończąc na Suspense i Streaming. Wskazano także na zalety i możliwości, jakie oferuje każda z tych technologii, podkreślając ich znaczenie w tworzeniu efektywnych i nowoczesnych aplikacji internetowych.Mamy nadzieję, że nasz przewodnik po renderowaniu w Next.js był dla Ciebie ciekawą przygodą. Ale nie zatrzymujemy się na tym! Czekają na Ciebie kolejne fascynujące tematy.

Zapraszamy do lektury naszego następnego artykułu Pobieranie danych w Next.js - Przewodnik dla początkujących. Dowiesz się z niego, jak efektywnie pracować z danymi, co jest kluczowe w tworzeniu dynamicznych aplikacji.

Często zadawane pytania

  1. Czym różni się Server Component od Client Component w Next.js? Server Components są renderowane na serwerze i zazwyczaj służą do statycznych części aplikacji, jak np. nawigacja czy wstępne ładowanie danych. Client Components renderowane są po stronie klienta i używane do dynamicznych, interaktywnych części aplikacji, takich jak koszyki sklepowe, karuzele czy animacje.
  2. Jak Suspense i Streaming wpływają na wydajność aplikacji w Next.js? Suspense i Streaming pozwalają na ładowanie aplikacji w sposób bardziej płynny i efektywny. Dzięki nim można wcześniej wyświetlać części strony, zanim wszystkie komponenty zostaną załadowane, co poprawia doświadczenie użytkownika i zmniejsza czas oczekiwania.
  3. Czy mogę używać Server Components do bezpośredniego połączenia z bazą danych? Tak, Server Components umożliwiają bezpośrednie użycie async/await, co jest wygodne przy pobieraniu danych bezpośrednio w komponencie.
  4. Jakie są główne korzyści z używania Server Components? Główne korzyści to lepsza wydajność poprzez zmniejszenie rozmiaru pakietów wysyłanych do klienta, większe bezpieczeństwo poprzez utrzymanie wrażliwych danych na serwerze oraz efektywniejsze pobieranie danych.
  5. Czy Client Components mają dostęp do API przeglądarki? Tak, Client Components mają pełny dostęp do API przeglądarki, co pozwala na tworzenie zaawansowanych, interaktywnych interfejsów użytkownika dostosowanych do konkretnych przypadków użycia.
  6. W jaki sposób można korzystać z 'use client' w Next.js? Aby użyć Client Components, należy dodać deklarację 'use client' na początku pliku. Oznacza to, że wszystkie komponenty w tym pliku będą traktowane jako część pakietu klienta i będą renderowane po stronie klienta.
  7. Jakie są najlepsze praktyki w połączeniu Server Components i Client Components? Najlepszą praktyką jest używanie Server Components dla części aplikacji, które nie wymagają interakcji z użytkownikiem i mogą być renderowane statycznie, takie jak nawigacja czy informacje o produkcie. Client Components są najlepsze dla dynamicznych i interaktywnych elementów, takich jak karuzele, filtry czy animacje. Ważne jest, aby znaleźć właściwą równowagę między obydwoma typami komponentów, zależnie od potrzeb aplikacji i użytkownika.
Bartosz Lewandowski

Bartosz Lewandowski

Next.js/Shopify Developer

Newsletter

Obserwuj nas