Um den Anforderungen verschiedener Benutzertypen gerecht zu werden, sind Webanwendungen wahrscheinlich mit mehr Code erforderlich, als für einen Benutzertyp, damit die App unterschiedliche Szenarien und Anwendungsfälle handhaben und sich an diese anpassen kann, was zu neuen Funktionen und Funktionalitäten führt. Wenn dies geschieht, ist es vernünftig zu erwarten, dass die Leistung einer App mit wachsender Codebasis abnimmt.
Code-Splitting ist eine Technik, bei der eine Anwendung nur den Code lädt, den sie gerade benötigt, und nichts weiter. Wenn ein Benutzer beispielsweise zur Homepage navigiert, besteht wahrscheinlich keine Notwendigkeit, den Code zu laden, der ein Backend-Dashboard antreibt. Mit Code-Splitting können wir sicherstellen, dass nur der Code für die Homepage geladen wird und der Ballast für ein optimaleres Laden draußen bleibt.
Code-Splitting ist in einer React-Anwendung mit React Loadable möglich. Es bietet eine Higher-Order-Komponente, die so eingerichtet werden kann, dass spezifische Komponenten zu spezifischen Zeiten dynamisch importiert werden.
Komponentensplitting
Es gibt Situationen, in denen wir eine Komponente bedingt rendern möchten, basierend auf einem Benutzerereignis, sagen wir, wenn sich ein Benutzer bei einem Konto anmeldet. Eine gängige Methode, dies zu handhaben, ist die Verwendung von State – die Komponente wird je nach Anmeldestatus der App gerendert. Wir nennen dies Komponentensplitting.
Schauen wir uns an, wie das im Code aussehen würde.
Siehe den Pen
React-Loadable von Kingsley Silas Chijioke (@kinsomicrote)
auf CodePen.
Als grundlegendes Beispiel sagen wir, wir möchten eine Komponente bedingt rendern, die eine <h2>-Überschrift mit "Hallo" enthält. So etwas:
const Hello = () => {
return (
<React.Fragment>
<h2>Hello</h2>
</React.Fragment>
)
}
Wir können einen openHello-State in der App-Komponente mit dem Anfangswert false haben. Dann können wir einen Button haben, der zum Umschalten des States verwendet wird, entweder um die Komponente anzuzeigen oder auszublenden. Das werfen wir in eine handleHello-Methode, die so aussieht:
class App extends React.Component {
state = {
openHello: false
}
handleHello = () => {
this.setState({ openHello: !this.state.openHello })
}
render() {
return (
<div className="App">
<button onClick={this.handleHello}>
Toggle Component
</button>
{
this.state.openHello ?
<Hello />
: null
}
</div>
);
}
}
Werfen Sie einen kurzen Blick in die DevTools und achten Sie auf den Network-Tab.

Lassen Sie uns jetzt refaktorieren, um LoadableHello zu verwenden. Anstatt die Komponente direkt zu importieren, werden wir den Import mit Loadable durchführen. Wir beginnen mit der Installation des react-loadable-Pakets.
## yarn, npm or however you roll
yarn add react-loadable
Nachdem das zu unserem Projekt hinzugefügt wurde, müssen wir es in die App importieren.
import Loadable from 'react-loadable';
Wir werden Loadable verwenden, um eine "Lade"-Komponente zu erstellen, die so aussehen wird:
const LoadableHello = Loadable({
loader: () => import('./Hello'),
loading() {
return <div>Loading...</div>
}
})
Wir übergeben eine Funktion als Wert für loader, die die zuvor erstellte Hello-Komponente zurückgibt, und wir verwenden import(), um sie dynamisch zu importieren. Die Fallback-Benutzeroberfläche, die wir rendern möchten, bevor die Komponente importiert wird, wird von loading() zurückgegeben. In diesem Beispiel geben wir ein div-Element zurück, obwohl wir auch eine Komponente hineinlegen können, wenn wir möchten.
Anstatt die Hello-Komponente direkt in der App-Komponente einzufügen, werden wir LoadableHello die Aufgabe übertragen, so dass die bedingte Anweisung so aussehen wird:
{
this.state.openHello ?
<LoadableHello />
: null
}
Schauen Sie sich das an – jetzt wird unsere Hello-Komponente erst dann in das DOM geladen, wenn der State durch den Button umgeschaltet wird.

Und das ist Komponentensplitting: die Fähigkeit, eine Komponente zu laden, um eine andere asynchron zu laden!
Routenbasiertes Splitting
Nun, wir haben gesehen, wie Loadable verwendet werden kann, um Komponenten über andere Komponenten zu laden. Eine weitere Möglichkeit ist die Verwendung von routenbasiertem Splitting. Der Unterschied hier ist, dass Komponenten entsprechend der aktuellen Route geladen werden.
Wenn sich ein Benutzer also auf der Homepage einer App befindet und auf eine Hello-Ansicht mit der Route /hello klickt, werden nur die Komponenten geladen, die zu dieser Route gehören. Dies ist eine ziemlich gängige Methode, um Splitting in vielen Apps zu handhaben, und funktioniert im Allgemeinen gut, insbesondere in weniger komplexen Anwendungen.
Hier ist ein einfaches Beispiel für definierte Routen in einer App. In diesem Fall haben wir zwei Routen: (1) Home (/) und (2) Hello (/hello).
class App extends Component {
render() {
return (
<div className="App">
<BrowserRouter>
<div>
<Link to="/">Home</Link>
<Link to="/hello">Hello</Link>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/hello" component={Hello} />
</Switch>
</div>
</BrowserRouter>
</div>
);
}
}
Wie die Dinge nun stehen, werden alle Komponenten gerendert, wenn ein Benutzer die Pfade wechselt, obwohl wir die eine Hello-Komponente basierend auf diesem Pfad rendern möchten. Sicher, es ist keine große Sache, wenn wir von ein paar Komponenten sprechen, aber es könnte definitiv so sein, wenn mehr Komponenten hinzugefügt werden und die Anwendung größer wird.
Mit Loadable können wir nur die Komponente importieren, die wir möchten, indem wir für jede eine ladbare Komponente erstellen.
const LoadableHello = Loadable({
loader: () => import('./Hello'),
loading() {
return <div>Loading...</div>
}
})
const LoadableHome = Loadable({
loader: () => import('./Home'),
loading() {
return <div>Loading...</div>
}
})
class App extends Component {
render() {
return (
<div className="App">
<BrowserRouter>
<div>
<Link to="/">Home</Link>
<Link to="/hello">Hello</Link>
<Switch>
<Route exact path="/" component={LoadableHome} />
<Route path="/hello" component={LoadableHello} />
</Switch>
</div>
</BrowserRouter>
</div>
);
}
}
Jetzt liefern wir den richtigen Code zur richtigen Zeit. Danke, Loadable!
Was ist mit Fehlern und Verzögerungen?
Wenn die importierte Komponente schnell geladen wird, besteht keine Notwendigkeit, eine "Lade"-Komponente anzuzeigen. Glücklicherweise kann Loadable die Anzeige der Ladekomponente verzögern. Dies ist hilfreich, um zu verhindern, dass sie zu früh angezeigt wird, wo sie albern wirkt, und stattdessen nach einer beachtlichen Zeit angezeigt wird, in der wir erwarten würden, sie geladen zu haben.
Um das zu tun, wird unsere Beispiel-Loadable-Komponente so aussehen:
const LoadableHello = Loadable({
loader: () => import('./Hello'),
loading: Loader,
delay: 300
})
Hier übergeben wir die Hello-Komponente als Wert für loading, die über loader importiert wird. Standardmäßig ist delay auf 200ms eingestellt, aber wir haben unsere auf etwas später auf 300ms gesetzt.
Fügen wir nun eine Bedingung zur Loader-Komponente hinzu, die ihr sagt, dass sie den Loader erst nach Ablauf der eingestellten 300ms Verzögerung anzeigen soll.
const Loader = (props) => {
if (props.pastDelay) {
return <h2>Loading...</h2>
} else {
return null
}
}
Die Loader-Komponente wird also nur angezeigt, wenn die Hello-Komponente nach 300ms nicht angezeigt wird.
react-loader gibt uns auch eine error-Prop, die wir verwenden können, um aufgetretene Fehler zurückzugeben. Und da es sich um eine Prop handelt, können wir sie alles ausgeben lassen, was wir wollen.
const Loader = (props) => {
if (props.error) {
return <div>Oh no, something went wrong!</div>;
} else if (props.delay) {
return <h2>Loading...</h2>
} else {
return null;
}
}
Beachten Sie, dass wir hier tatsächlich Verzögerung und Fehlerbehandlung kombinieren! Wenn sofort ein Fehler auftritt, zeigen wir eine Meldung an. Wenn kein Fehler vorliegt, aber 300 ms vergangen sind, zeigen wir einen Loader an. Andernfalls laden Sie bitte die Hello-Komponente!
Das war's!
Ist es nicht großartig, dass wir heute mehr Freiheit und Flexibilität haben, wie wir Code laden und anzeigen? Code-Splitting – sei es nach Komponente oder nach Route – ist die Art von Sache, für die React entwickelt wurde. React ermöglicht es uns, modulare Komponenten zu schreiben, die isolierten Code enthalten, und wir können sie jederzeit und überall bereitstellen und sie mit dem DOM und anderen Komponenten interagieren lassen. Sehr cool!
Hoffentlich gibt Ihnen dies einen guten Eindruck vom Code-Splitting als Konzept. Wenn Sie damit beginnen, ist es hilfreich, sich eingehendere Artikel anzusehen, um ein tieferes Verständnis des Konzepts zu erlangen.
- React Loadable GitHub Repo – Ein perfekter Ort, um die gesamte detaillierte Dokumentation zu erhalten.
- Introducing React Loadable – Ein großartiger Überblick vom Autor der Bibliothek.
- React Loadable auf Frontend Masters – Ein Kurs von Brian Holt (Abonnement erforderlich)
- Reacts experimentelle Suspense-API – Eine Einführung in eine weitere Möglichkeit, Ladezustände zu behandeln.
- Vergleich mit React.lazy – Es gibt Überschneidungen zwischen beiden, und dieser Beitrag erklärt, wo sie sich unterscheiden.
Es fühlt sich an, als ob Apps früher so gebaut wurden und React immer wieder Funktionen hinzufügt, um sie so funktionieren zu lassen, wie Apps schon immer funktioniert haben. Früher gab es einen Seiten-Refresh. Das ist nicht wirklich viel anders.
Außerdem funktioniert Vue so schon von Haus aus. (ohne Kompilierung)
Der gute Aspekt solcher Dinge ist, dass wir uns von monolithischen Anwendungen, die monströse Build-Umgebungen und Unmengen von Abhängigkeiten erfordern, weg bewegen. Der Wettbewerb in der Frontend-Framework-Umgebung treibt dies voran, und ich bin froh zu sehen, dass React mithält, das ist gut für alle.
Wie verhält sich das im Vergleich zu React.Lazy? Scheint eine ähnliche Funktionalität zu haben, warum also diese Methode einer integrierten React-Methode vorziehen?
Hallo Preston! Am Ende des Beitrags gibt es einen nützlichen Link zu einem Artikel, der den Unterschied gut erklärt: https://www.smooth-code.com/open-source/loadable-components/docs/loadable-vs-react-lazy/
@Preston Server-Side Rendering
Im letzten Link, den Sie angegeben haben (der mit dem Vergleich mit React.Lazy), heißt es, dass react-loadable nicht mehr gepflegt wird und wir auf eine andere Bibliothek umsteigen sollten.
@loadable/component wird in den React-Dokumenten empfohlen, wenn Sie Server-Rendering wünschen.
https://reactjs.org/docs/code-splitting.html#reactlazy
react-loadable scheint in letzter Zeit nicht mehr gepflegt worden zu sein. Eine weitere Option ist React Async Component, das bei mir gut funktioniert hat, obwohl Dan Abramov uns kürzlich davor oder vor einer seiner Abhängigkeiten gewarnt hat. Ich habe irgendwo gelesen, dass Server-Rendering für Suspense in Zukunft geplant ist, aber derzeit nicht unterstützt wird, weshalb React.Lazy keine gute Wahl für SR ist.
Hey Kingsley, toller Artikel!
Können Sie bitte klarstellen, was im Abschnitt Route-Based Splitting Folgendes bedeutet:
Bedeutet das, dass beim Wechseln der Pfade derzeit alle Komponenten für beide Pfade geladen werden, oder dass alle Komponenten in der App geladen werden?