Podział kodu za pomocą React.lazy i Susense

Nie musisz wysyłać do użytkowników więcej kodu niż to konieczne, więc podziel swoje pakiety, aby mieć pewność, że nigdy tak się nie stanie.

Metoda React.lazy ułatwia dzielenie kodu aplikacji React na poziomie komponentów za pomocą importów dynamicznych.

import React, { lazy } from 'react';

const AvatarComponent = lazy(() => import('./AvatarComponent'));

const DetailsComponent = () => (
  <div>
    <AvatarComponent />
  </div>
)

Dlaczego to jest przydatne?

Duża aplikacja React zwykle składa się z wielu komponentów, metod pomocniczych i bibliotek innych firm. Jeśli nie podejmiesz wysiłków, aby wczytywać różne części aplikacji tylko wtedy, gdy są potrzebne, użytkownicy otrzymają jeden duży pakiet kodu JavaScript, gdy tylko wczytają pierwszą stronę. Może to znacząco wpłynąć na wydajność strony.

Funkcja React.lazy zapewnia wbudowany sposób na oddzielanie komponentów aplikacji do oddzielnych fragmentów kodu JavaScript przy minimalnym nakładzie pracy. Następnie możesz zadbać o wczytywanie stanów, gdy połączysz komponent Suspense.

Suspens

Problem z przesyłaniem dużych ładunków JavaScriptu do użytkowników polega na tym, że wczytywanie strony trwa długo, zwłaszcza na słabszych urządzeniach i przy słabszych połączeniach sieciowych. Dlatego dzielenie kodu i opóźnione wczytywanie są bardzo przydatne.

Jednak zawsze występuje niewielkie opóźnienie, gdy komponent podzielony na części jest pobierany przez sieć, dlatego ważne jest wyświetlanie przydatnego stanu wczytywania. Aby rozwiązać ten problem, użyj komponentu React.lazy z elementem Suspense.

import React, { lazy, Suspense } from 'react';

const AvatarComponent = lazy(() => import('./AvatarComponent'));

const renderLoader = () => <p>Loading</p>;

const DetailsComponent = () => (
  <Suspense fallback={renderLoader()}>
    <AvatarComponent />
  </Suspense>
)

Suspense przyjmuje komponent fallback, co pozwala wyświetlać dowolny komponent React jako stan wczytywania. Poniżej znajdziesz przykład, który pokazuje, jak to działa. Tylko po kliknięciu przycisku następuje renderowanie awatara. Wtedy wysyłane jest żądanie kodu niezbędnego do zawieszenia AvatarComponent. W międzyczasie wyświetlany jest komponent wczytywania zastępczego.

Kod, który tworzy AvatarComponent, jest mały, dlatego wskaźnik ładowania jest widoczny tylko przez krótki czas. Wczytywanie większych komponentów może trwać znacznie dłużej, zwłaszcza w przypadku słabego połączenia z siecią.

Aby lepiej zrozumieć, jak to działa:

  • Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie kliknij Pełny ekran pełny ekran.
  • Aby otworzyć Narzędzia dla programistów, naciśnij `Control+Shift+J` (lub `Command+Option+J` na Macu).
  • Kliknij kartę Sieć.
  • Kliknij menu Ograniczanie, które domyślnie jest ustawione na Brak ograniczania. Wybierz Szybkie 3G.
  • W aplikacji kliknij przycisk Kliknij mnie.

Wskaźnik wczytywania będzie teraz widoczny dłużej. Zwróć uwagę, że cały kod, z którego składa się AvatarComponent, jest pobierany jako osobny fragment.

Panel sieci w Narzędziach dla programistów pokazujący pobieranie pliku chunk.js

Zawieszanie wielu komponentów

Kolejną funkcją Suspense jest możliwość zawieszenia wczytywania wielu komponentów nawet wtedy, gdy są one wczytywane z opóźnieniem.

Na przykład:

import React, { lazy, Suspense } from 'react';

const AvatarComponent = lazy(() => import('./AvatarComponent'));
const InfoComponent = lazy(() => import('./InfoComponent'));
const MoreInfoComponent = lazy(() => import('./MoreInfoComponent'));

const renderLoader = () => <p>Loading</p>;

const DetailsComponent = () => (
  <Suspense fallback={renderLoader()}>
    <AvatarComponent />
    <InfoComponent />
    <MoreInfoComponent />
  </Suspense>
)

To bardzo przydatny sposób na opóźnienie renderowania wielu komponentów przy jednoczesnym wyświetlaniu tylko jednego stanu wczytywania. Gdy wszystkie komponenty zostaną pobrane, użytkownik zobaczy je wszystkie wyświetlone w tym samym czasie.

Możesz to sprawdzić, korzystając z tego kodu embedowania:

Bez tego łatwo napotkać problem przerywanego wczytywania lub wczytywania różnych części interfejsu po kolei, z własnym wskaźnikiem wczytywania dla każdej z nich. Może to powodować nieprzyjemne wrażenia podczas korzystania z aplikacji.

Obsługa błędów wczytywania

Suspense pozwala wyświetlić tymczasowy stan wczytywania, gdy w tle wysyłane są żądania sieciowe. Co jednak, jeśli te żądania sieciowe nie powiedzie się z jakiegoś powodu? Możesz być offline lub Twoja aplikacja internetowa próbuje zlazy-loadować adres URL wersji, który jest nieaktualny i niedostępny po ponownym wdrożeniu na serwerze.

React ma standardowy wzorzec postępowania w przypadku tych typów błędów wczytywania: używa on granicy błędów. Jak opisano w dokumentacji, każdy komponent React może pełnić funkcję granicy błędów, jeśli implementuje jedną (lub obie) z metod cyklu życia static getDerivedStateFromError() lub componentDidCatch().

Aby wykrywać i obsługiwać błędy wczytywania opóźnionego, możesz otoczyć komponent Suspense komponentami nadrzędnymi, które będą pełnić funkcję granicy błędów. W metodzie render() granicy błędu możesz renderować elementy potomne w postaci domyślnej, jeśli nie ma błędu, lub renderować niestandardowy komunikat o błędzie, jeśli coś pójdzie nie tak:

import React, { lazy, Suspense } from 'react';

const AvatarComponent = lazy(() => import('./AvatarComponent'));
const InfoComponent = lazy(() => import('./InfoComponent'));
const MoreInfoComponent = lazy(() => import('./MoreInfoComponent'));

const renderLoader = () => <p>Loading</p>;

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = {hasError: false};
  }

  static getDerivedStateFromError(error) {
    return {hasError: true};
  }

  render() {
    if (this.state.hasError) {
      return <p>Loading failed! Please reload.</p>;
    }

    return this.props.children;
  }
}

const DetailsComponent = () => (
  <ErrorBoundary>
    <Suspense fallback={renderLoader()}>
      <AvatarComponent />
      <InfoComponent />
      <MoreInfoComponent />
    </Suspense>
  </ErrorBoundary>
)

Podsumowanie

Jeśli nie wiesz, od czego zacząć stosowanie podziału kodu w aplikacji React, wykonaj te czynności:

  1. Zacznij od poziomu trasy. Trasy to najprostszy sposób na identyfikację punktów aplikacji, które można podzielić. Dokumenty React pokazują, jak używać Suspense razem z react-router.
  2. Określ wszystkie duże komponenty na stronie w Twojej witrynie, które renderują się tylko w przypadku określonych interakcji użytkowników (np. kliknięcia przycisku). Podział tych komponentów pozwoli zminimalizować ładunki JavaScript.
  3. Zastanów się nad podziałem innych elementów, które znajdują się poza ekranem i nie są kluczowe dla użytkownika.