Vous n'avez jamais besoin de fournir plus de code que nécessaire à vos utilisateurs, alors divisez vos bundles pour éviter que cela n'arrive.
La méthode React.lazy
permet de diviser facilement le code d'une application React au niveau des composants à l'aide d'importations dynamiques.
import React, { lazy } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const DetailsComponent = () => (
<div>
<AvatarComponent />
</div>
)
En quoi est-ce utile ?
Une grande application React comprend généralement de nombreux composants, méthodes d'utilité et bibliothèques tierces. S'il n'est pas possible de charger différentes parties d'une application uniquement lorsqu'elles sont nécessaires, un seul bundle de JavaScript volumineux sera envoyé aux utilisateurs dès qu'ils chargent la première page. Cela peut avoir un impact significatif sur les performances de la page.
La fonction React.lazy
fournit un moyen intégré de séparer les composants d'une application en blocs distincts de code JavaScript avec très peu d'efforts. Vous pouvez ensuite gérer les états de chargement lorsque vous l'associez au composant Suspense
.
Suspense
Le problème de l'envoi d'une charge utile JavaScript importante aux utilisateurs est la durée de chargement de la page, en particulier sur les appareils et les connexions réseau moins performants. C'est pourquoi le fractionnement du code et le chargement différé sont extrêmement utiles.
Toutefois, les utilisateurs devront toujours subir un léger retard lorsqu'un composant de fractionnement de code est extrait sur le réseau. Il est donc important d'afficher un état de chargement utile. L'utilisation de React.lazy
avec le composant Suspense
permet de résoudre ce problème.
import React, { lazy, Suspense } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const renderLoader = () => <p>Loading</p>;
const DetailsComponent = () => (
<Suspense fallback={renderLoader()}>
<AvatarComponent />
</Suspense>
)
Suspense
accepte un composant fallback
qui vous permet d'afficher n'importe quel composant React en tant qu'état de chargement. L'exemple suivant montre comment procéder.
L'avatar n'est affiché que lorsque vous cliquez sur le bouton, où une requête est alors effectuée pour récupérer le code nécessaire pour l'AvatarComponent
suspendue.
En attendant, le composant de chargement de remplacement s'affiche.
Ici, le code qui compose AvatarComponent
est petit, c'est pourquoi l'icône de chargement ne s'affiche que pendant une courte période. Le chargement des composants plus volumineux peut prendre beaucoup plus de temps, en particulier sur les connexions réseau faibles.
Pour mieux comprendre ce fonctionnement:
- Pour prévisualiser le site, appuyez sur Afficher l'application, puis sur Plein écran .
- Appuyez sur Ctrl+Maj+J (ou Cmd+Option+J sur Mac) pour ouvrir DevTools.
- Cliquez sur l'onglet Réseau.
- Cliquez sur le menu déroulant Limitation, qui est défini sur Pas de limitation par défaut. Sélectionnez 3G rapide.
- Cliquez sur le bouton Cliquez ici dans l'application.
L'indicateur de chargement s'affiche encore plus longtemps. Notez que tout le code qui compose AvatarComponent
est récupéré sous la forme d'un bloc distinct.
Suspendre plusieurs composants
Une autre fonctionnalité de Suspense
est qu'elle vous permet de suspendre le chargement de plusieurs composants, même s'ils sont tous chargés de manière différée.
Exemple :
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>
)
Il s'agit d'un moyen extrêmement utile de retarder l'affichage de plusieurs composants tout en n'affichant qu'un seul état de chargement. Une fois que tous les composants ont été récupérés, l'utilisateur peut les voir tous affichés en même temps.
Vous pouvez le voir avec l'intégration suivante:
Sans cela, vous risquez de rencontrer le problème de chargement fractionné, ou de voir différentes parties d'une UI se charger l'une après l'autre, chacune ayant son propre indicateur de chargement. Cela peut rendre l'expérience utilisateur plus désagréable.
Gérer les échecs de chargement
Suspense
vous permet d'afficher un état de chargement temporaire pendant que des requêtes réseau sont effectuées en arrière-plan. Mais que se passe-t-il si ces requêtes réseau échouent pour une raison quelconque ? Vous êtes peut-être hors connexion, ou votre application Web tente de charger de manière différée une URL versionnée obsolète et non plus disponible après un redéploiement de serveur.
React dispose d'un modèle standard pour gérer correctement ces types d'échecs de chargement: à l'aide d'une limite d'erreur. Comme décrit dans la documentation, tout composant React peut servir de limite d'erreur s'il implémente l'une (ou les deux) des méthodes de cycle de vie static getDerivedStateFromError()
ou componentDidCatch()
.
Pour détecter et gérer les échecs de chargement paresseux, vous pouvez encapsuler votre composant Suspense
avec un composant parent qui sert de limite d'erreur. Dans la méthode render()
de la limite d'erreur, vous pouvez afficher les enfants tels quels en l'absence d'erreur ou afficher un message d'erreur personnalisé en cas de problème:
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>
)
Conclusion
Si vous ne savez pas par où commencer à appliquer le fractionnement du code à votre application React, procédez comme suit:
- Commencez au niveau de l'itinéraire. Les routes sont le moyen le plus simple d'identifier les points de votre application qui peuvent être divisés. La documentation React montre comment utiliser
Suspense
avecreact-router
. - Identifiez les composants volumineux d'une page de votre site qui ne s'affichent que lors de certaines interactions utilisateur (par exemple, lorsque l'utilisateur clique sur un bouton). En divisant ces composants, vous réduirez vos charges utiles JavaScript.
- Envisagez de diviser tout autre élément qui n'est pas à l'écran et qui n'est pas essentiel pour l'utilisateur.