Verwendung von React Loadable für Code-Splitting nach Komponenten und Routen

Avatar of Kingsley Silas
Kingsley Silas am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

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.