W ostatnim czasie NextJS zyskuje coraz większą popularność jako sposób na tworzenie aplikacji React. Z pewnością duży wpływ na to ma fakt, że NextJS oferuje kilka różnych strategii pobierania danych.
A są to:
Renderowanie po stronie klienta: CSR,
Renderowanie po stronie serwera: SSR,
Statyczne renderowanie strony: SSG,
Przyrostowa regeneracja statyczna: ISR.
NextJS, w przeciwieństwie do zwykłej aplikacji React, oferuje funkcję zwaną pre-renderowaniem. Oznacza to, że wstępnie renderowany HTML jest wyświetlany podczas początkowego ładowania. W tradycyjnych aplikacjach React cała aplikacja jest ładowana i renderowana po stronie klienta. Następnie, po załadowaniu JS kod aplikacja staje się interaktywna.
Generacja statyczna
W SSG HTML jest generowany w czasie kompilacji i ponownie wykorzystywany dla każdego żądania. Po utworzeniu kompilacji produkcyjnej każde żądanie będzie ponownie wykorzystywać ten statycznie wygenerowany plik HTML.
Istnieją również dwa rodzaje generowania statycznego: z danymi i bez danych.
W pierwszym przypadku HTML zostanie wygenerowany po pobraniu danych przez rozwiązanie obietnicy. W tym przypadku możemy użyć metody pobierania danych getStaticProps... ale tylko jeśli używasz Next.js 9.3 lub nowszego. Jeśli nie, pomyśl o aktualizacji, ponieważ starsza metoda getInitialProps nie jest już zalecana i będzie przestarzała. Metoda ta jest również wywoływana w każdej nawigacji po stronie klienta, więc nie jest wydajna, jeśli nie chcesz pobierać danych przy każdym żądaniu.
Naprawdę fajną rzeczą jest nowo wydana funkcja o nazwie ISR (Incremental Static Regeneration), która jest czymś pomiędzy SSG i SSR. Pozwala ona (przy użyciu określonego klucza o nazwie revalidate) na przyrostową regenerację strony. Oznacza to, że dzięki temu kluczowi nie trzeba przebudowywać aplikacji za każdym razem, gdy chcemy uzyskać aktualizację danych pobranych z serwera. Wystarczy dodać klucz revalidate z okresem rewalidacji w sekundach.
Oznacza to, że jeśli żądanie nadejdzie po tym okresie, to ponownie pobierze dane z serwera.
Inną sytuacją jest użycie dynamicznej strony, której ścieżka zależy od zewnętrznych danych. W takim przypadku możemy użyć metody getStaticPaths informującej, które trasy dynamiczne powinny zostać wstępnie załadowane:
export async const getStaticProps = ({ params }) => {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`);
const post = await res.json();
return {
props: { post },
};
}
Istnieje dobry sposób na sprawdzenie, które trasy dynamiczne zostały utworzone. Możesz uruchomić następną kompilację i następny eksport, a następnie będziesz mieć statyczną wersję swojej aplikacji w nowo utworzonym katalogu out.
Po uruchomieniu kolejnego eksportu możemy zauważyć w obu przypadkach (z i bez ograniczonej liczby ścieżek) różną liczbę postów znalezionych w my-appoutposts.
Przyjrzyjmy się teraz bliżej kluczowemu i wymaganemu parametrowi awaryjnemu. Mówi on, co zrobić, jeśli strona nie została wstępnie renderowana w czasie kompilacji. Jeśli jest ustawiony na true, getStaticProps uruchamia i generuje tę stronę. Jeśli false, otrzymamy 404 po próbie załadowania tej konkretnej ścieżki. Kolejna rzecz: strony z fallback, które są włączone w getStaticPaths nie mogą być eksportowane.
Poniżej znajdują się wyniki próby załadowania tej samej strony dynamicznej w obu przypadkach:
Pierwszy przypadek (bez ograniczonych ścieżek)
Drugi przypadek (z ograniczonymi ścieżkami i ustawieniem awaryjnym na false)
Drugi przypadek (z ograniczonymi ścieżkami i ustawieniem awaryjnym na true)
Renderowanie po stronie serwera
Główna różnica w stosunku do SSG: nowy HTML jest generowany przy każdym żądaniu. Jest używany głównie wtedy, gdy pobieramy dane zewnętrzne. W takim przypadku nie ma potrzeby przebudowywania aplikacji za każdym razem, gdy chcemy zaktualizować dane z serwera.
Metoda getServerSideProps wygląda bardzo podobnie do getStaticProps. Różnica polega na tym, że getServerSideProps działa przy każdym żądaniu, podczas gdy getStaticProps działa raz w czasie kompilacji.
Renderowanie po stronie klienta
W przypadku renderowania po stronie klienta początkowe ładowanie strony jest nieco powolne. Komunikacja z serwerem odbywa się w czasie wykonywania. Można to zrobić w bardziej tradycyjny sposób:
Możemy również skorzystać z innego rozwiązania, 'swr' - React Hooks library for data fetching by Vercel*, które jest mocno rekomendowane przez twórców NextJS. SWR to skrót od State While Revalidate.
import useSWR from "swr";
const Blog = () => {
const fetcher = (url) => fetch(url).then((r) => r.json());
const { data: posts = [], error } = useSWR(
"https://jsonplaceholder.typicode.com/posts", fetcher);
if (error) return <div>Nie udało się załadować postów</div>;
if (!posts.length) return <div>ładowanie...</div>;
return (
<>
{posts.map((post) => (
{post.title}
))}
</>
}
Podsumowanie
NextJS daje nam dodatkową możliwość wyboru, której ze strategii pobierania danych chcemy użyć na każdej stronie. Nie musimy stosować tylko jednego rozwiązania dla całej aplikacji.
Skrót
getServerSideProps - gdy trzeba wstępnie wyrenderować aplikację przy każdym żądaniu z pobranymi danymi
getStaticProps - gdy dane mogą być pobierane raz w czasie kompilacji i używane przy każdym żądaniu bez aktualizacji
getInitialProps - niezalecane, będzie przestarzałe
getStaticPaths - do wstępnego renderowania ścieżek dynamicznych