Fractionnement du code avec React.lazy et Suspense

Vous n'avez jamais besoin de fournir plus de code que nécessaire à vos utilisateurs, alors divisez vos bundles pour éviter que cela ne se produise.

La méthode React.lazy permet de diviser facilement le code d'une application React au niveau d'une au niveau du composant à 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 est généralement composée de nombreux composants, utilitaires de méthodes et de bibliothèques tierces. Si aucun effort n'est fait pour tenter de charger différentes parties d'une application uniquement lorsqu'elles sont nécessaires. Le bundle de JavaScript sera envoyé aux utilisateurs dès qu'ils auront chargé le première page. Cela peut avoir une incidence significative sur les performances des pages.

La fonction React.lazy fournit un moyen intégré de séparer les composants dans un l'application en fragments distincts de JavaScript avec très peu de travail. Vous pouvez gère ensuite les états de chargement lorsque vous l'associez à Suspense .

Suspense

Le problème avec l'envoi d'une charge utile JavaScript volumineuse aux utilisateurs est la longueur de Temps nécessaire au chargement complet de la page, en particulier sur les appareils moins performants et des connexions réseau. C'est pourquoi le fractionnement du code et le chargement différé sont extrêmement utile.

Cependant, il y aura toujours un léger retard pour les utilisateurs lorsque un composant de fractionnement de code est récupéré sur le réseau. Il est donc important afficher un état de chargement utile. Utiliser React.lazy avec 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 élément React. en tant qu'état de chargement. L'exemple suivant illustre ce fonctionnement. L'avatar ne s'affiche que lorsque l'utilisateur clique sur le bouton, lorsqu'une requête est puis effectué pour récupérer le code nécessaire au AvatarComponent suspendu. En attendant, le composant de chargement de remplacement s'affiche.

Ici, le code qui compose AvatarComponent est petit, ce qui signifie pourquoi l'icône de chargement ne s'affiche que pendant un court laps de temps. Plus grande composants peut prendre beaucoup plus de temps à charger, des connexions réseau faibles.

Pour mieux illustrer comment cela fonctionne:

  • Pour prévisualiser le site, appuyez sur Afficher l'application. Appuyez ensuite sur Plein écran plein écran
  • Appuyez sur Ctrl+Maj+J (ou Cmd+Option+J sur Mac) pour ouvrir les outils de développement.
  • Cliquez sur l'onglet Réseau.
  • Cliquez sur le menu déroulant Limitation, défini par défaut sur Aucune limitation. Sélectionnez 3G rapide.
  • Cliquez sur le bouton Cliquez ici dans l'application.

L'indicateur de chargement s'affiche encore plus longtemps. Remarquez comment tout le code composant AvatarComponent est récupérée sous la forme d'un fragment distinct.

<ph type="x-smartling-placeholder">
</ph> Panneau réseau des outils de développement montrant le téléchargement d&#39;un fichier fragment.js

Suspendre plusieurs composants

Une autre fonctionnalité de Suspense est qu'elle vous permet de suspendre plusieurs de chargement des composants, même s'ils sont tous à chargement différé.

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

C'est 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 terminé l'extraction, l'utilisateur peut les voir tous affichés en même temps.

Vous pouvez le voir avec l'élément intégré suivant:

Sans cela, vous rencontrerez facilement le problème de chargement échelonné. différentes parties d'une interface utilisateur se chargent l'une après l'autre, chacune ayant ses propres indicateur de chargement. Cela peut rendre l'expérience utilisateur plus bouleversante.

Gérer les échecs de chargement

Suspense vous permet d'afficher un état de chargement temporaire des requêtes sont effectuées en arrière-plan. Mais que se passe-t-il si ces requêtes réseau échouent une raison quelconque ? Il se peut que vous soyez hors connexion ou que votre application Web effectuer le chargement différé d'une URL avec gestion des versions ; qui sont obsolètes et ne sont plus disponibles après un redéploiement du serveur.

React propose un schéma standard pour gérer facilement ces types de chargements les défaillances: en utilisant une limite d'erreur. Comme indiqué dans la documentation, tout composant React peut servir de limite d'erreur s'il implémente l'une des deux les deux) des méthodes de cycle de vie static getDerivedStateFromError() ou componentDidCatch()

Pour détecter et gérer les échecs de chargement différé, vous pouvez encapsuler votre Suspense avec un composant parent servant de limite d'erreur. Au cœur de la la méthode render() de la limite d'erreur, vous pouvez afficher les éléments enfants tels quels s'il existe aucune 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 pour appliquer le fractionnement de code à votre React , procédez comme suit:

  1. Commencez au niveau de l'itinéraire. Les routes constituent le moyen le plus simple d'identifier les points pour votre application, qui peuvent être divisées. La Documents React montre comment utiliser Suspense avec react-router
  2. Identifiez tous les composants volumineux d'une page de votre site qui s'affichent uniquement sur certaines interactions utilisateur (comme un clic sur un bouton). Division de ces réduira vos charges utiles JavaScript.
  3. Envisagez de diviser tout autre élément hors écran qui n'est pas essentiel pour la utilisateur.