Réagissez au suspense dans la pratique | Astuces CSS


Ce message vise à comprendre comment fonctionne Suspense, ce qu’il fait et à voir comment il peut s’intégrer dans une véritable application Web. Nous verrons comment intégrer routage et chargement des données avec Le suspense dans React. Pour le routage, j’utiliserai du JavaScript vanille et j’utiliserai le mien micro-graphql-react Bibliothèque GraphQL pour les données.

Si vous vous demandez React Router, cela semble génial, mais je n’ai jamais eu l’occasion de l’utiliser. Mon propre projet parallèle a une histoire de routage assez simple pour que je le fasse toujours à la main. De plus, l’utilisation de JavaScript vanilla nous donnera un meilleur aperçu du fonctionnement de Suspense.

Un peu de fond

Parlons de Suspense lui-même. Kingsley Silas en donne un aperçu complet, mais la première chose à noter est qu’il s’agit toujours d’une API expérimentale. Cela signifie – et Les documents de React en disent autant – ne pas s’y appuyer encore pour un travail prêt pour la production. Il y a toujours une chance que cela change entre maintenant et quand il sera complètement terminé, alors gardez cela à l’esprit.

Cela dit, Suspense consiste à maintenir une interface utilisateur cohérente face aux dépendances asynchrones, telles que les composants React chargés paresseusement, les données GraphQL, etc. Suspense fournit des API de bas niveau qui vous permettent de maintenir facilement votre interface utilisateur pendant que votre application gère ces des choses.

Mais que signifie “cohérent” dans ce cas? Ça veut dire ne pas rendre une interface utilisateur partiellement terminée. Cela signifie que s’il y a trois sources de données sur la page et que l’une d’elles est terminée, nous ne le fais pas voulez rendre ce morceau d’état mis à jour, avec un spinner à côté des deux autres morceaux d’état maintenant obsolètes.

Ce que nous faire que vous voulez faire est d’indiquer à l’utilisateur que les données sont en cours de chargement, tout en continuant à afficher soit l’ancienne interface utilisateur, soit une autre interface utilisateur qui indique que nous attendons des données; Suspense prend en charge l’un ou l’autre, dans lequel j’entrerai.

Que fait exactement Suspense

C’est moins compliqué qu’il n’y paraît. Traditionnellement, dans React, vous définissez l’état et votre interface utilisateur est mise à jour. La vie était simple. Mais cela a également conduit aux sortes d’incohérences décrites ci-dessus. Ce que Suspense ajoute, c’est la possibilité qu’un composant informe React au moment du rendu qu’il attend des données asynchrones; cela s’appelle la suspension, et cela peut se produire n’importe où dans l’arborescence d’un composant, autant de fois que nécessaire, jusqu’à ce que l’arborescence soit prête. Lorsqu’un composant se suspend, React refuse de rendre la mise à jour de l’état en attente jusqu’à ce que toutes les dépendances suspendues soient satisfaites.

Que se passe-t-il donc lorsqu’un composant est suspendu? React recherchera l’arbre, trouvera le premier et rendre son remplacement. Je vais vous fournir de nombreux exemples, mais pour l’instant, sachez que vous pouvez fournir ceci:

}>

…et le composant sera rendu si des composants enfants de sont suspendus.

Mais que se passe-t-il si nous avons déjà une interface utilisateur valide et cohérente et que l’utilisateur charge de nouvelles données, provoquant la suspension d’un composant? Cela entraînerait le retrait de l’intégralité de l’interface utilisateur existante et l’affichage du remplacement. Ce serait toujours cohérent, mais pas une bonne UX. Nous préférons que l’ancienne interface utilisateur reste à l’écran pendant le chargement des nouvelles données.

Pour prendre en charge cela, React fournit une deuxième API, useTransition, qui effectue effectivement un changement d’état en mémoire. En d’autres termes, il vous permet de définir l’état en mémoire tout en gardant votre interface utilisateur existante à l’écran; React gardera littéralement une deuxième copie de votre arborescence de composants rendue en mémoire et définira l’état sur cette arbre. Les composants peuvent être suspendus, mais uniquement en mémoire, de sorte que votre interface utilisateur existante continuera de s’afficher à l’écran. Une fois le changement d’état terminé et toutes les suspensions résolues, le changement d’état en mémoire s’affiche à l’écran. De toute évidence, vous souhaitez fournir des commentaires à votre utilisateur pendant que cela se produit, donc useTransition fournit un pending booléen, que vous pouvez utiliser pour afficher une sorte de notification de “chargement” en ligne pendant la résolution des suspensions en mémoire.

Quand vous y pensez, vous ne voulez probablement pas que votre interface utilisateur existante s’affiche indéfiniment pendant que votre chargement est en attente. Si l’utilisateur essaie de faire quelque chose et qu’une longue période de temps s’écoule avant qu’il ne soit terminé, vous devriez probablement considérer l’interface utilisateur existante comme obsolète et non valide. À ce stade, vous avez probablement volonté voulez que votre arborescence de composants soit suspendue, et repli à afficher.

Pour y parvenir, useTransition prend un timeoutMs valeur. Cela indique la durée pendant laquelle vous êtes prêt à laisser le changement d’état en mémoire s’exécuter, avant de suspendre.

const Component = props => {
  const [startTransition, isPending] = useTransition({ timeoutMs: 3000 });
  // .....
};

Ici, startTransition est une fonction. Lorsque vous souhaitez exécuter un changement d’état “en mémoire”, vous appelez startTransitionet passez une expression lambda qui modifie votre état.

startTransition(() => {
  dispatch({ type: LOAD_DATA_OR_SOMETHING, value: 42 });
})

Tu peux appeler startTransition où tu veux. Vous pouvez le transmettre aux composants enfants, etc. Lorsque vous l’appelez, tout changement d’état que vous effectuez se produit en mémoire. En cas de suspension, isPending deviendra vrai, que vous pouvez utiliser pour afficher une sorte d’indicateur de chargement en ligne.

C’est ça. C’est ce que fait Suspense.

Le reste de cet article va entrer dans du code réel pour tirer parti de ces fonctionnalités.

Exemple: navigation

Pour lier la navigation à Suspense, vous serez heureux de savoir que React fournit une primitive pour ce faire: React.lazy. C’est une fonction qui prend une expression lambda qui renvoie une promesse, qui se résout en un composant React. Le résultat de cet appel de fonction devient votre composant chargé paresseusement. Cela semble compliqué, mais cela ressemble à ceci:

const SettingsComponent = lazy(() => import("./modules/settings/settings"));

SettingsComponent est maintenant un composant React qui, une fois rendu (mais pas avant), appellera la fonction que nous avons passée, qui appellera import() et chargez le module JavaScript situé à ./modules/settings/settings.

La pièce maîtresse est la suivante: alors que import() est en vol, le rendu du composant SettingsComponent suspendra. Il semble que nous ayons toutes les pièces en main, alors rassemblons-les et construisons une navigation basée sur Suspense.

Aides à la navigation

Mais d’abord, pour le contexte, je vais brièvement expliquer comment l’état de navigation est géré dans cette application, de sorte que le code Suspense aura plus de sens.

Je vais utiliser mon application de liste de lecture. C’est juste un projet parallèle que je garde principalement pour jouer avec la technologie Web de pointe. Il a été écrit par moi seul, alors attendez-vous à ce que certaines parties soient un peu raffinées (en particulier la conception).

L’application est petite, avec environ huit modules différents qu’un utilisateur peut parcourir, sans navigation plus approfondie. Tout état de recherche qu’un module peut utiliser est stocké dans la chaîne de requête de l’URL. Dans cet esprit, il existe quelques méthodes qui effacent le nom du module actuel et recherchent l’état à partir de l’URL. Ce code utilise le query-string et history packages de npm, et ressemble un peu à ceci (certains détails ont été supprimés pour plus de simplicité, comme l’authentification).

import createHistory from "history/createBrowserHistory";
import queryString from "query-string";
export const history = createHistory();
export function getCurrentUrlState() {
  let location = history.location;
  let parsed = queryString.parse(location.search);
  return {
    pathname: location.pathname,
    searchState: parsed
  };
}
export function getCurrentModuleFromUrl() {
  let location = history.location;
  return location.pathname.replace(///g, "").toLowerCase();
}

j’ai un appSettings réducteur qui détient le module actuel et searchState valeurs pour l’application et utilise ces méthodes pour se synchroniser avec l’URL si nécessaire.

Les morceaux d’une navigation basée sur le suspense

Commençons par un travail de suspense. Tout d’abord, créons les composants paresseux pour nos modules.

const ActivateComponent = lazy(() => import("./modules/activate/activate"));
const AuthenticateComponent = lazy(() =>
  import("./modules/authenticate/authenticate")
);
const BooksComponent = lazy(() => import("./modules/books/books"));
const HomeComponent = lazy(() => import("./modules/home/home"));
const ScanComponent = lazy(() => import("./modules/scan/scan"));
const SubjectsComponent = lazy(() => import("./modules/subjects/subjects"));
const SettingsComponent = lazy(() => import("./modules/settings/settings"));
const AdminComponent = lazy(() => import("./modules/admin/admin"));

Maintenant, nous avons besoin d’une méthode qui choisit le bon composant en fonction du module actuel. Si nous utilisions React Router, nous aurions de belles Composants. Puisque nous roulons cela manuellement, un switch ça ira.

export const getModuleComponent = moduleToLoad => {
  if (moduleToLoad == null) {
    return null;
  }
  switch (moduleToLoad.toLowerCase()) {
    case "activate":
      return ActivateComponent;
    case "authenticate":
      return AuthenticateComponent;
    case "books":
      return BooksComponent;
    case "home":
      return HomeComponent;
    case "scan":
      return ScanComponent;
    case "subjects":
      return SubjectsComponent;
    case "settings":
      return SettingsComponent;
    case "admin":
      return AdminComponent;
  }
  
  return HomeComponent;
};

Le tout mis en place

Avec toute la configuration ennuyeuse à l’écart, voyons à quoi ressemble la racine de l’application entière. Il y a beaucoup de code ici, mais je vous le promets, relativement peu de ces lignes se rapportent à Suspense, et je couvrirai tout cela.

const App = () => {
  const [startTransitionNewModule, isNewModulePending] = useTransition({
    timeoutMs: 3000
  });
  const [startTransitionModuleUpdate, moduleUpdatePending] = useTransition({
    timeoutMs: 3000
  });
  let appStatePacket = useAppState();
  let [appState, _, dispatch] = appStatePacket;
  let Component = getModuleComponent(appState.module);
  useEffect(() => {
    startTransitionNewModule(() => {
      dispatch({ type: URL_SYNC });
    });
  }, []);
  useEffect(() => {
    return history.listen(location => {
      if (appState.module != getCurrentModuleFromUrl()) {
        startTransitionNewModule(() => {
          dispatch({ type: URL_SYNC });
        });
      } else {
        startTransitionModuleUpdate(() => {
          dispatch({ type: URL_SYNC });
        });
      }
    });
  }, [appState.module]);
  return (
    
      
        
                    {isNewModulePending ? : null}           }>            
              {Component ? : null}            
         
       
     
   
  ); };

Premièrement, nous avons deux appels différents à useTransition. Nous en utiliserons un pour le routage vers un nouveau module, et l’autre pour mettre à jour l’état de recherche du module actuel. Pourquoi la différence? Eh bien, lorsque l’état de recherche d’un module est mis à jour, ce module voudra probablement afficher un indicateur de chargement en ligne. Cet état de mise à jour est détenu par le moduleUpdatePending variable, que vous verrez que je mets en contexte pour le module actif à saisir, et utiliser au besoin:

    {isNewModulePending ? : null}   }>    
      {Component ? : null} // highlight    
 

le appStatePacket est le résultat du réducteur d’état de l’application dont j’ai discuté ci-dessus (mais ne l’a pas montré). Il contient divers éléments de l’état de l’application qui changent rarement (thème de couleur, état hors ligne, module actuel, etc.).

let appStatePacket = useAppState();

Un peu plus tard, je récupère le composant qui se trouve être actif, en fonction du nom du module actuel. Initialement, ce sera nul.

let Component = getModuleComponent(appState.module);

Le premier appel à useEffect dira à notre appSettings réducteur à synchroniser avec l’URL au démarrage.

useEffect(() => {
  startTransitionNewModule(() => {
    dispatch({ type: URL_SYNC });
  });
}, []);

Comme il s’agit du module initial vers lequel l’application Web navigue, je l’enveloppe startTransitionNewModule pour indiquer qu’un nouveau module est en cours de chargement. Bien qu’il soit tentant d’avoir le appSettings réducteur ont le nom de module initial comme son état initial, ce qui nous empêche d’appeler notre startTransitionNewModule rappel, ce qui signifie que notre limite Suspense rendrait le repli immédiatement, plutôt qu’après le délai d’expiration.

Le prochain appel à useEffect configure un abonnement historique. Quoi qu’il en soit, lorsque l’URL change, nous demandons à nos paramètres d’application de se synchroniser avec l’URL. La seule différence est startTransition ce même appel est enveloppé.

useEffect(() => {
  return history.listen(location => {
    if (appState.module != getCurrentModuleFromUrl()) {
      startTransitionNewModule(() => {
        dispatch({ type: URL_SYNC });
      });
    } else {
      startTransitionModuleUpdate(() => {
        dispatch({ type: URL_SYNC });
      });
    }
  });
}, [appState.module]);

Si nous naviguons vers un nouveau module, nous appelons startTransitionNewModule. Si nous chargeons un composant qui n’a pas déjà été chargé, React.lazy sera suspendu et l’indicateur en attente visible uniquement à la racine de l’application sera défini, ce qui affichera un spinner de chargement en haut de l’application pendant que le composant paresseux est récupéré et chargé. À cause de la façon dont useTransition fonctionne, l’écran actuel continuera à s’afficher pendant trois secondes. Si ce délai expire et que le composant n’est toujours pas prêt, notre interface utilisateur sera suspendue et le repli s’affichera, ce qui affichera le composant:

{isNewModulePending ?  : null}
}>
  
    {Component ? : null}  

Si nous ne changeons pas de modules, nous appelons startTransitionModuleUpdate:

startTransitionModuleUpdate(() => {
  dispatch({ type: URL_SYNC });
});

Si la mise à jour entraîne une suspension, l’indicateur en attente que nous mettons en contexte sera déclenché. Le composant actif peut le détecter et afficher l’indicateur de chargement en ligne qu’il souhaite. Comme précédemment, si la suspension dure plus de trois secondes, la même limite de suspense d’avant sera déclenchée … à moins, comme nous le verrons plus loin, qu’il y ait une limite de suspense plus bas dans l’arborescence.

Une chose importante à noter est que ces délais d’attente de trois secondes s’appliquent non seulement au chargement des composants, mais aussi à être prêts à être affichés. Si le composant se charge en deux secondes, et, lors du rendu en mémoire (puisque nous sommes à l’intérieur d’un startTransition appel) suspend, le useTransition volonté continuer d’attendre jusqu’à une seconde de plus avant de suspendre.

En écrivant ce billet de blog, j’ai utilisé les modes réseau lents de Chrome pour aider à forcer le chargement à être lent, pour tester mes limites Suspense. Les paramètres se trouvent dans l’onglet Réseau des outils de développement de Chrome.

Ouvrons notre application au module des paramètres. Cela s’appellera:

dispatch({ type: URL_SYNC });

Notre appSettings le réducteur se synchronisera avec l’URL, puis définira le module sur “Paramètres”. Cela se produira à l’intérieur de startTransitionNewModule de sorte que, lorsque le composant chargé paresseux tente de s’afficher, il se suspend. Puisque nous sommes à l’intérieur startTransitionNewModule, les isNewModulePending va basculer vers true, et le le composant sera rendu.

Si le composant n’est toujours pas prêt à être rendu dans les trois secondes, la version en mémoire de notre arborescence de composants basculera, se suspendra et notre limite de suspense rendra le composant.
Une fois terminé, le module des paramètres s’affichera.

Alors, que se passe-t-il lorsque nous parcourons un nouveau site? Fondamentalement, la même chose qu’avant, sauf cet appel:

dispatch({ type: URL_SYNC });

… Proviendra de la deuxième instance de useEffect. Parcourons le module livres et voyons ce qui se passe. Tout d’abord, le spinner en ligne affiche comme prévu:

Si le délai de trois secondes s’écoule, notre limite de suspense rendra son repli:
Et, finalement, notre module de livres se charge:

Recherche et mise à jour

Restons dans le module livres et mettons à jour la chaîne de recherche d’URL pour lancer une nouvelle recherche. Rappelons avant que nous détections le même module dans cette seconde useEffect appeler et en utilisant un dédié useTransition appelez-le. À partir de là, nous plaçions l’indicateur en attente dans le contexte du module actif à saisir et à utiliser.

Voyons un peu de code pour l’utiliser réellement. Il n’y a pas vraiment beaucoup de code lié à Suspense ici. Je saisis la valeur du contexte et, si cela est vrai, je rend un spinner en ligne au-dessus de mes résultats existants. Rappelons que cela se produit lorsqu’un useTransition l’appel a commencé et l’application est suspendue en mémoire. Pendant ce temps, nous continuons d’afficher l’interface utilisateur existante, mais avec cet indicateur de chargement.

const BookResults: SFC<{ books: any; uiView: any }> = ({ books, uiView }) => {
  const isUpdating = useContext(ModuleUpdateContext);
  return (
    <>
      {!books.length ? (
        
No books found
) : null} {isUpdating ? : null} {uiView.isGridView ? ( ) : uiView.isBasicList ? ( ) : uiView.isCoversList ? ( ) : null} ); };

Définissons un terme de recherche et voyons ce qui se passe. Tout d’abord, le spinner en ligne s’affiche.

Ensuite, si le useTransition le délai expire, nous obtiendrons le repli de la limite Suspense. Le module livres définit sa propre limite de suspense afin de fournir un indicateur de chargement plus précis, qui ressemble à ceci:

Ceci est un point clé. Lorsque vous effectuez des substitutions de limites Suspense, essayez de ne pas lancer de message de type spinner et de «chargement». Cela avait du sens pour notre navigation de haut niveau car il n’y a pas grand-chose d’autre à faire. Mais lorsque vous vous trouvez dans une partie spécifique de votre application, essayez de faire en sorte que votre solution de secours réutilise bon nombre des mêmes composants avec une sorte d’indicateur de chargement où les données seraient – mais avec tout le reste désactivé.

Voici à quoi ressemblent les composants pertinents pour mon module de livres:

const RenderModule: SFC<{}> = ({}) => {
  const uiView = useBookSearchUiView();
  const [lastBookResults, setLastBookResults] = useState({
    totalPages: 0,
    resultsCount: 0
  });
  return (
    
}>
); }; const Fallback: SFC<{ uiView: BookSearchUiView; totalPages: number; resultsCount: number; }> = ({ uiView, totalPages, resultsCount }) => { return ( <> {uiView.isGridView ? ( ) : (

Books are loading

)} ); };

Une note rapide sur la cohérence

Avant de poursuivre, j’aimerais souligner une chose des captures d’écran précédentes. Regardez le spinner en ligne qui s’affiche pendant que la recherche est en attente, puis regardez l’écran lorsque cette recherche est suspendue, puis les résultats finaux:

Remarquez comment il y a une étiquette “C ++” à droite du volet de recherche, avec une option pour le supprimer de la requête de recherche? Ou plutôt, remarquez comment cette étiquette se trouve uniquement sur les deux secondes captures d’écran? Au moment où l’URL est mise à jour, l’état de l’application régissant cette étiquette est mis à jour; cependant, cet état ne s’affiche pas initialement. Initialement, la mise à jour d’état est suspendue en mémoire (puisque nous avons utilisé useTransition), et avant L’interface utilisateur continue de montrer.

Ensuite, le repli est rendu. La solution de secours affiche une version désactivée de cette même barre de recherche, qui affiche l’état de recherche actuel (par choix). Nous avons maintenant supprimé notre interface utilisateur précédente (car elle est maintenant assez ancienne et périmée) et attendons la recherche affichée dans la barre de menus désactivée.

C’est le genre de cohérence que Suspense vous offre gratuitement.

Vous pouvez passer votre temps à créer de beaux états d’application, et React fait le travail de jambe en supposant que les choses sont prêtes, sans que vous ayez besoin de jongler avec des promesses.

Limites de suspens imbriquées

Supposons que notre navigation de niveau supérieur prenne un certain temps pour charger notre composant de livres dans la mesure où notre spinner «Toujours en charge, désolé» de la frontière Suspense s’affiche. À partir de là, le composant livres se charge et la nouvelle limite Suspense à l’intérieur du composant livres s’affiche. Mais, alors que le rendu continue, notre requête de recherche de livre se déclenche et se suspend. Que va-t-il se passer? La limite de suspense de niveau supérieur continuera-t-elle à s’afficher jusqu’à ce que tout soit prêt, ou la limite de suspense inférieure dans les livres prendra-t-elle le dessus?

La réponse est la dernière. Au fur et à mesure que les nouvelles limites du suspense s’affaiblissent dans l’arbre, leur repli remplacer le repli de tout repli de suspense antécédent montrait déjà. Il existe actuellement une API instable pour remplacer cela, mais si vous faites un bon travail de conception de vos solutions de rechange, c’est probablement le comportement que vous souhaitez. Vous ne voulez pas que «Toujours en cours de chargement, désolé» continue de s’afficher. Au contraire, dès que le composant livres est prêt, vous voulez absolument afficher ce shell avec le message d’attente le plus ciblé.

Maintenant, que se passe-t-il si notre module de livres se charge et commence à s’afficher pendant que startTransition spinner est toujours à l’affiche et se suspend ensuite? En d’autres termes, imaginez que notre startTransition a un délai d’expiration de trois secondes, le composant livres s’affiche, la limite suspendue imbriquée se trouve dans l’arborescence des composants après une seconde et la requête de recherche s’arrête. Les deux secondes restantes s’écouleront-elles avant que cette nouvelle limite suspendue imbriquée ne rende le repli, ou le repli apparaîtra-t-il immédiatement? La réponse, peut-être surprenante, est que la nouvelle solution de rechange Suspense s’affichera immédiatement par défaut. En effet, il est préférable d’afficher une nouvelle interface utilisateur valide aussi rapidement que possible, afin que l’utilisateur puisse voir que les choses se produisent et progressent.

Comment les données s’intègrent

La navigation est bonne, mais comment le chargement des données s’inscrit-il dans tout cela?

Il s’intègre complètement et de manière transparente. Le chargement des données déclenche des suspensions tout comme la navigation avec React.lazy, et il se raccorde tout de même useTransition et limites de suspense. C’est ce qui est si étonnant avec Suspense: toutes vos dépendances asynchrones fonctionnent de manière transparente dans ce même système. La gestion manuelle de ces diverses demandes asynchrones pour garantir la cohérence était un cauchemar avant Suspense, c’est précisément pourquoi personne ne l’a fait. Les applications Web étaient connues pour les filateurs en cascade qui s’arrêtaient à des moments imprévisibles, produisant des interfaces utilisateur incohérentes qui n’étaient que partiellement terminées.

OK, mais comment lier le chargement des données à cela? Le chargement de données dans Suspense est paradoxalement à la fois plus complexe et aussi simple.

Je vais t’expliquer.

Si vous attendez des données, vous lancerez une promesse dans le composant qui lit (ou tente de lire) les données. La promesse doit être cohérente en fonction de la demande de données. Ainsi, quatre demandes répétées pour cette même requête de recherche “C ++” devraient lancer la même promesse identique. Cela implique une sorte de couche de mise en cache pour gérer tout cela. Vous n’écrirez probablement pas cela vous-même. Au lieu de cela, vous espérez et attendez que la bibliothèque de données que vous utilisez se mette à jour pour prendre en charge Suspense.

Cela se fait déjà dans mon micro-graphql-react bibliothèque. Au lieu d’utiliser le useQuery crochet, vous utiliserez le useSuspenseQuery hook, qui a une API identique, mais jette une promesse cohérente lorsque vous attendez des données.

Attendez, qu’en est-il du préchargement?!

Votre cerveau s’est-il transformé en bouillie en lisant d’autres choses sur Suspense qui parlaient de cascades, de récupération sur le rendu, de préchargement, etc.? Ne t’en fais pas. Voici ce que tout cela signifie.

Disons que vous chargez paresseusement le composant livres, ce qui rend puis demande des données, ce qui provoque un nouveau suspense. La demande de réseau pour le composant et la demande de réseau pour les données se feront l’une après l’autre, à la manière d’une cascade.

Mais voici la partie clé: l’état de l’application qui a conduit à la requête initiale exécutée lorsque le composant chargé était déjà disponible lorsque vous avez commencé à charger le composant (qui, dans ce cas, est l’URL). Alors pourquoi ne pas “lancer” la requête dès que vous savez que vous en aurez besoin? Dès que vous accédez à /books, pourquoi ne pas déclencher la requête de recherche actuelle juste là et là, donc elle est déjà en vol lorsque le composant se charge.

Le module micro-graphql-react a en effet un preload méthode, et je vous invite à l’utiliser. Le préchargement des données est une belle optimisation des performances, mais cela n’a rien à voir avec Suspense. Les applications Classic React pourraient (et devraient) précharger les données dès qu’elles savent qu’elles en auront besoin. Les applications Vue devraient précharger les données dès qu’elles savent qu’elles en auront besoin. Les applications Svelte devraient … vous obtenez le point.

Le préchargement des données est orthogonal à Suspense, ce que vous pouvez faire avec n’importe quel framework. C’est aussi quelque chose que nous aurions tous dû déjà faire, même si personne d’autre ne l’était.

Mais sérieusement, comment préchargez-vous?

C’est à toi de voir. À tout le moins, la logique pour exécuter la recherche actuelle doit absolument être complètement séparée en son propre module autonome. Vous devez littéralement vous assurer que cette fonction de préchargement se trouve dans un fichier lui-même. Ne comptez pas sur Webpack pour faire trembler les arbres; vous serez probablement confronté à une tristesse abjecte la prochaine fois que vous auditerez vos offres groupées.

Tu as un preload() dans son propre bundle, alors appelez-la. Appelez-le lorsque vous savez que vous êtes sur le point de naviguer vers ce module. Je suppose que React Router a une sorte d’API pour exécuter du code lors d’un changement de navigation. Pour le code de routage vanille ci-dessus, j’appelle la méthode dans ce commutateur de routage d’avant. Je l’avais omis par souci de concision, mais l’entrée dans les livres ressemble en fait à ceci:

switch (moduleToLoad.toLowerCase()) {
  case "activate":
    return ActivateComponent;
  case "authenticate":
    return AuthenticateComponent;
  case "books":
    // preload!!!
    booksPreload();
    return BooksComponent;

C’est ça. Voici une démo en direct pour jouer avec:

Pour modifier la valeur du délai d’attente, qui est par défaut 3000 ms, accédez à Paramètres et consultez l’onglet divers. Assurez-vous simplement de rafraîchir la page après l’avoir modifiée.

Emballer

J’ai rarement été aussi excité pour quoi que ce soit dans l’écosystème de développement Web comme je le suis pour Suspense. C’est un système incroyablement ambitieux pour gérer l’un des problèmes les plus délicats du développement Web: l’asynchronie.

Close Menu