Codeaufteilung mit React.lazy und Suspense

Sie sollten Ihren Nutzern nie mehr Code als nötig senden. Teilen Sie Ihre Bundles daher auf, damit das nicht passiert.

Mit der Methode React.lazy können Sie eine React-Anwendung mithilfe dynamischer Importe ganz einfach auf Komponentenebene codieren.

import React, { lazy } from 'react';

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

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

Welchen Nutzen bieten sie?

Eine große React-Anwendung besteht in der Regel aus vielen Komponenten, Dienstmethoden und Drittanbieterbibliotheken. Wenn nicht versucht wird, verschiedene Teile einer Anwendung nur dann zu laden, wenn sie benötigt werden, wird ein einzelnes großes JavaScript-Bundle an Ihre Nutzer gesendet, sobald sie die erste Seite laden. Das kann sich erheblich auf die Seitenleistung auswirken.

Die React.lazy-Funktion bietet eine integrierte Möglichkeit, Komponenten in einer Anwendung mit wenig Aufwand in separate JavaScript-Chunks zu unterteilen. Sie können dann den Status laden, wenn Sie die Komponente mit Suspense verknüpfen.

Spannung

Das Problem beim Senden einer großen JavaScript-Nutzlast an Nutzer ist die lange Ladezeit der Seite, insbesondere auf leistungsschwächeren Geräten und Netzwerkverbindungen. Aus diesem Grund sind Code-Splitting und Lazy Loading äußerst nützlich.

Es gibt jedoch immer eine kleine Verzögerung, wenn eine Code-Split-Komponente über das Netzwerk abgerufen wird. Daher ist es wichtig, einen nützlichen Ladestatus anzuzeigen. Mit React.lazy und der Komponente Suspense lässt sich dieses Problem beheben.

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

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

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

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

Suspense akzeptiert eine fallback-Komponente, mit der Sie eine beliebige React-Komponente als Ladestatus anzeigen können. Das folgende Beispiel zeigt, wie das funktioniert. Der Avatar wird nur gerendert, wenn auf die Schaltfläche geklickt wird. Daraufhin wird eine Anfrage gesendet, um den für die gesperrte AvatarComponent erforderlichen Code abzurufen. In der Zwischenzeit wird die Fallback-Ladekomponente angezeigt.

Hier ist der Code, aus dem AvatarComponent besteht, klein, weshalb das Ladesymbol nur für kurze Zeit angezeigt wird. Bei größeren Komponenten kann das Laden viel länger dauern, insbesondere bei schwachen Netzwerkverbindungen.

Zur Veranschaulichung:

  • Wenn Sie sich eine Vorschau der Website ansehen möchten, drücken Sie App ansehen und dann Vollbild Vollbild.
  • Drücken Sie „Strg + Umschalttaste + J“ (oder „Befehlstaste + Optionstaste + J“ auf einem Mac), um die Entwicklertools zu öffnen.
  • Klicken Sie auf den Tab Netzwerk.
  • Klicken Sie auf das Drop-down-Menü Drosselung. Standardmäßig ist Keine Drosselung ausgewählt. Wählen Sie Schnelles 3G aus.
  • Klicken Sie in der App auf die Schaltfläche Click Me (Klicken Sie auf mich).

Die Ladeanzeige wird jetzt länger angezeigt. Beachten Sie, dass der gesamte Code, aus dem die AvatarComponent besteht, als separater Teil abgerufen wird.

Netzwerkbereich in den DevTools, in dem eine chunk.js-Datei heruntergeladen wird

Mehrere Komponenten pausieren

Mit Suspense können Sie außerdem das Laden mehrerer Komponenten pausieren, auch wenn sie alle mit Lazy Loading geladen werden.

Beispiel:

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>
)

Dies ist eine äußerst nützliche Möglichkeit, das Rendern mehrerer Komponenten zu verzögern und dabei nur einen einzigen Ladevorgang anzuzeigen. Sobald alle Komponenten abgerufen wurden, werden sie dem Nutzer gleichzeitig angezeigt.

Das sieht so aus:

Andernfalls kann es leicht zu einem gestupften Laden kommen, bei dem verschiedene Teile einer Benutzeroberfläche nacheinander geladen werden und jeder eine eigene Ladeanzeige hat. Das kann die Nutzerfreundlichkeit beeinträchtigen.

Fehler beim Laden beheben

Mit Suspense können Sie einen vorübergehenden Ladestatus anzeigen lassen, während im Hintergrund Netzwerkanfragen gesendet werden. Was aber, wenn diese Netzwerkanfragen aus irgendeinem Grund fehlschlagen? Möglicherweise sind Sie offline oder Ihre Webanwendung versucht, eine versionierte URL per Lazy-Load zu laden, die veraltet ist und nach einer Serverneubereitstellung nicht mehr verfügbar ist.

React bietet ein Standardmuster für die fehlerfreie Verarbeitung dieser Art von Ladefehlern: die Verwendung einer Fehlergrenze. Wie in der Dokumentation beschrieben, kann jede React-Komponente als Fehlergrenze dienen, wenn sie eine oder beide Lebenszyklusmethoden static getDerivedStateFromError() oder componentDidCatch() implementiert.

Um Fehler beim Lazy Loading zu erkennen und zu behandeln, können Sie Ihre Suspense-Komponente in eine übergeordnete Komponente einbetten, die als Fehlergrenze dient. Innerhalb der render()-Methode der Fehlergrenze können Sie die untergeordneten Elemente unverändert rendern, wenn kein Fehler auftritt, oder eine benutzerdefinierte Fehlermeldung, wenn etwas schiefgeht:

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>
)

Fazit

Wenn Sie sich nicht sicher sind, wo Sie mit dem Code-Splitting für Ihre React-Anwendung beginnen sollen, gehen Sie so vor:

  1. Beginnen Sie auf Routenebene. Mithilfe von Routen können Sie am einfachsten Stellen in Ihrer Anwendung identifizieren, die aufgeteilt werden können. In den React-Dokumenten wird gezeigt, wie Suspense zusammen mit react-router verwendet werden kann.
  2. Suchen Sie nach großen Komponenten auf einer Seite Ihrer Website, die nur bei bestimmten Nutzerinteraktionen gerendert werden, z. B. beim Klicken auf eine Schaltfläche. Durch die Aufteilung dieser Komponenten werden Ihre JavaScript-Nutzlasten minimiert.
  3. Alles andere, was nicht auf dem Bildschirm zu sehen ist und für den Nutzer nicht wichtig ist, sollte aufgeteilt werden.