Images pré-caches avec react suspense
La fonction de suspense de React est passionnante, et elle arrive, et permettra aux développeurs de retarder facilement le rendu de leurs composants jusqu'à ce qu'ils soient «prêts», ce qui entraîne une expérience utilisateur plus fluide. "Préparer" peut se référer à de nombreux aspects ici. Par exemple, votre utilitaire de chargement de données peut être utilisé en conjonction avec le suspense pour permettre à l'état de charge cohérent d'être affiché pendant que toutes les données sont transférées sans suivre manuellement l'état de charge pour chaque requête. Ensuite, lorsque vos données sont disponibles et que votre composant est "prêt", il sera rendu. C'est le sujet qui est le plus souvent discuté avec le suspense, et j'en ai déjà écrit; Cependant, le chargement des données n'est que l'un des nombreux cas d'utilisation où le suspense peut améliorer l'expérience utilisateur. Un autre cas d'utilisation dont je veux parler aujourd'hui est le préchargement de l'image.
Avez-vous déjà créé ou utilisé une application Web où votre position se tremble et saute lorsque l'image est téléchargée et rendue en atteignant l'écran? Nous appelons cela un réarrangement de contenu, et il est à la fois choquant et désagréable. Le suspense peut aider à résoudre ce problème. Saviez-vous que j'ai dit que l'intérêt du suspense est d'empêcher le rendu des composants jusqu'à ce qu'il soit prêt? Heureusement, "Ready" est très ouvert ici - à nos fins, il peut inclure "les images préchargées dont nous avons besoin". Voyons comment le faire!
Démarrage rapide à suspense
Avant de creuser dans les détails, comprenons rapidement le fonctionnement du suspense. Il a deux pièces principales. Tout d'abord, il y a le concept de compensation des composants. Cela signifie que React essaie de rendre notre composant, mais il n'est pas "prêt". Lorsque cela se produit, le "secours" le plus proche de l'arborescence des composants sera rendu. Nous verrons comment faire bientôt un report (ce qui est assez simple), mais le composant dit à React qu'il n'est pas encore prêt, c'est de lancer une promesse. React capturera la promesse, réalisera que le composant n'est pas encore prêt et rendra le secours. Lorsque Promise Parses, React essaiera de rendu à nouveau. Répéter ce processus. Oui, je suis un peu trop simplifié, mais c'est le but du fonctionnement du suspense, et nous développerons certains de ces concepts au fur et à mesure.
La deuxième partie du suspense est l'introduction d'une mise à jour de statut "transition". Cela signifie que nous définissons l'état, mais indique à React que les modifications d'état peuvent entraîner la suspension du composant, et si cela se produit, le secours n'est pas rendu. Au lieu de cela, nous voulons continuer à afficher l'écran actuel jusqu'à ce que la mise à jour d'état soit prête, à quel point elle sera rendu. Bien sûr, React nous fournit un indicateur booléen "en attente" qui permet aux développeurs de savoir que ce processus est en cours afin que nous puissions fournir des commentaires de charge en ligne.
Préchargeons-nous quelques images!
Tout d'abord, je tiens à souligner qu'il y a une démo complète que nous faisons à la fin de cet article. Si vous voulez juste sauter dans le code, n'hésitez pas à ouvrir la démo maintenant. Il montrera comment le suspense est utilisé en conjonction avec les mises à jour de l'état de transition vers les images de précharge. Le reste de ce post construira le code étape par étape et expliquera comment et pourquoi en cours de route.
Ok, commençons!
Nous voulons que nos composants soient suspendus jusqu'à ce que toutes les images soient préchargées. Pour simplifier l'opération autant que possible, créons un<suspenseimage></suspenseimage>
Composant, qui reçoit l'attribut SRC, précharge l'image, gère les lancers d'exception, puis rend un <img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/174358885649082.png" class="lazy" alt="Images pré-caches avec react suspense">
Utilisez des images dans HTML, mais nous pouvons également créer des images de manière impérative à l'aide Image()
dans JavaScript; De plus, l'image que nous créons de cette façon a un rappel onload
qui tire lorsque l'image ... est chargée. Cela ressemble à ceci:
const img = new image (); img.onload = () => { // L'image est chargée};
Mais comment le combinons-nous avec le lancer d'exception? Si vous êtes comme moi, vous pouvez d'abord penser à quelque chose comme ceci:
const suspenseImg = ({src, ... rest}) => { lancer une nouvelle promesse ((résolution) => { const img = new image (); img.onload = () => { résoudre(); }; img.src = src; }); Retour<img alt="" src="%7Bsrc%7D"> ; };
Le problème, bien sûr, est que cela mettra toujours une promesse. À chaque fois que réagir les tentatives de rendre<suspenseimg></suspenseimg>
Lorsqu'une instance est en cours, une nouvelle promesse est créée et lancée immédiatement. Au lieu de cela, nous voulons juste lancer une promesse avant le chargement de l'image. Il y a un vieux dicton que chaque problème en informatique peut être résolu en ajoutant une couche d'indirection (à l'exception du problème de trop de couches d'indirection), alors faisons-le et construisons un cache d'image. Lorsque nous lisons SRC, le cache vérifiera s'il a chargé l'image, et sinon, il commencera à précharger et lancera une exception. Et, si l'image est préchargée, elle reviendra vrai et permettra à React continuer à rendre notre image.
C'est à nous<suspenseimage></suspenseimage>
À quoi ressemble le composant:
export const SussenImg = ({src, ... rest}) => { imgcache.read (src); Retour<img src="%7Bsrc%7D" alt="Images pré-caches avec react suspense" > ; };
Voici à quoi ressemble la version minimale que nous avons mise en cache:
const imgcache = { __cache: {}, lire (src) { if (! ce cache .__ [src]) { ce cache .__ [src] = nouvelle promesse ((résolution) => { const img = new image (); img.onload = () => { Ce cache .__ [src] = true; Résolve (ce cache .__ [src]); }; img.src = src; }); } if (this .__ cache [src] instanceof promest) { Jetez ce cache .__ [src]; } Renvoie ce cache .__ [src]; } };
Ce n'est pas parfait, mais c'est suffisant pour l'instant. Continuons à l'utiliser.
accomplir
N'oubliez pas que ci-dessous est un lien vers une démo fonctionnelle complète, alors ne désespérez pas si je passe trop vite à une étape particulière. Nous expliquerons au fur et à mesure.
Commençons par définir notre secours. Nous définissons le secours en plaçant une balise de suspense dans l'arborescence des composants et passons notre attribut de secours. Tout composant en attente recherchera la balise de suspense la plus récente et rendra sa repli (mais si la balise de suspense n'est pas trouvée, une erreur sera lancée). Une véritable application peut avoir de nombreuses balises de suspense tout au long du processus, en définissant des secours spécifiques pour ses modules individuels, mais pour cette démonstration, nous n'avons besoin que d'une balise qui enveloppe notre application racine.
Function App () { Retour ( <suspense fallback="{<Loading"></suspense> }> <showimages></showimages> )); }
<loading></loading>
Les composants sont un spinner de base, mais dans les applications réelles, vous voudrez peut-être rendre une sorte de shell vide du composant que vous essayez réellement de rendre pour offrir une expérience plus transparente.
Avec ça, le nôtre<showimages></showimages>
Le composant rendra finalement notre image en utilisant les éléments suivants:
<div> {images.map ((img) => ( <div key="{img}"> <suspenseimg alt="" src="%7Bimg%7D"></suspenseimg> </div> ))} </div>
Lors du chargement initial, nos filateurs de chargement seront affichés jusqu'à ce que nos images initiales soient prêtes, à quel point elles seront affichées simultanément sans aucun décalage de réarrangement entrelacé.
Mise à jour de l'état de transition
Une fois les images en place, lorsque nous chargeons le prochain lot d'images, nous voulons qu'ils apparaissent après le chargement, bien sûr, en gardant l'image existante à l'écran au fur et à mesure qu'elles se chargent. Nous utilisons le crochet useTransition
pour ce faire. Cela renvoie une fonction startTransition
et un booléen isPending
qui indique que notre mise à jour de statut est en cours mais a été suspendue (ou même si elle n'a pas été suspendue, il peut toujours être vrai que si la mise à jour du statut prend trop de temps). Enfin, lorsque useTransition
est appelée, vous devez passer une valeur timeoutMs
, qui est le temps maximum que le drapeau isPending
peut être vrai, après quoi React abandonnera et rendra le secours (notez que timeoutMs
peut être supprimé dans un avenir proche, et lorsqu'un contenu existant est mis à jour, la mise à jour de l'état de transition n'a besoin qu'attendre plus de temps).
C'est à quoi je ressemble:
const [startTransition, isPending] = usetransition ({timeoutms: 10000});
Nous permettrons à 10 secondes de passer avant notre écran de repli, qui peut être trop long dans la vie réelle, mais convient à cette démonstration, surtout si vous pouvez délibérément ralentir le réseau dans Devtools pour l'expérimentation.
Voici comment l'utiliser. Lorsque vous cliquez sur le bouton qui charge plus d'images, le code ressemble à ceci:
startTransition (() => { setPage ((p) => p 1); });
Cette mise à jour d'état déclenchera une nouvelle charge de données à l'aide de mon client GraphQL Micro-GraphQL-React, qui est compatible avec le suspense et nous lancera une promesse lorsque la requête sera en cours. Une fois les données renvoyées, notre composant tentera de rendre et de se pencher à nouveau lorsque notre image sera préchargée. Bien que tout cela se produise, notre valeur isPending
sera vraie, ce qui nous permettra d'afficher le fileur de chargement en haut du contenu existant.
Évitez les cascades Internet
Vous vous demandez peut-être comment React peut bloquer le rendu pendant que le préchargement de l'image est en cours. En utilisant le code ci-dessus, lorsque nous faisons cela:
{images.map ((img) => (
... et qu'est-ce qui y est rendu<suspenseimage></suspenseimage>
, Réagira à rendre la première image, suspendre, puis réessayer la liste, dépasser la première image (maintenant dans notre cache), puis accrocher la deuxième image, alors la troisième, 4ème, etc. Si vous avez déjà lu sur la liste avant que tous ces rendus ne se demandent manuellement.
Il s'avère qu'il n'est pas nécessaire de s'inquiéter ou de faire un préchargement maladroit, car React est assez intelligent sur la façon dont cela rend les choses dans le monde du suspense. Lorsque React traverse notre arborescence de composants, il ne s'arrête pas lorsqu'il rencontre un en attente. Au lieu de cela, il continue d'essayer de rendre tous les autres chemins de notre arbre de composants. Alors oui, lorsqu'il essaie de rendre l'image 0, un hangage se produira, mais React continuera d'essayer de rendre l'image 1 à n avant sa pendaison.
Vous pouvez afficher cela en affichant l'onglet réseau dans la démo complète lorsqu'un nouvel ensemble d'images est chargé. Vous devriez voir l'intégralité du godet d'image affiché immédiatement dans la liste des réseaux, analysé un par un, et une fois terminé, les résultats doivent être affichés à l'écran. Pour vraiment amplifier cet effet, vous voudrez peut-être réduire la vitesse de votre réseau à "Fast 3G".
Pour le plaisir, nous pouvons forcer le suspense à traverser nos images en lisant manuellement chaque image de notre cache avant que React essaie de rendre nos composants, traversant chaque chemin de l'arborescence des composants.
images.ForEach ((img) => imgcache.read (img));
J'ai créé une démo pour illustrer cela. Si vous affichez également l'onglet réseau lors du chargement d'un nouvel ensemble d'images, vous verrez qu'ils sont ajoutés à la liste du réseau dans l'ordre (mais ne l'exécutez pas avec le ralentissement du réseau).
Hangage retardé
Lorsque vous utilisez le suspense, vous devez vous souvenir d'une inférence: suspendre le plus tard possible dans le rendu et le niveau inférieur de l'arborescence des composants. Si vous avez du rendu un tas d'images suspendues<imagelist></imagelist>
, assurez-vous que chaque image est suspendue dans son propre composant afin que la réaction puisse y accéder séparément afin qu'aucune image ne bloque d'autres images, ce qui entraîne une cascade.
La version de chargement des données de cette règle est que les données doivent être chargées autant que possible par les composants qui les nécessitent réellement. Cela signifie que nous devons éviter de faire ce qui suit dans un composant:
const {data1} = usUsUspenseQuery (query1, vars1); const {data2} = usUsSpenseSquery (query2, vars2);
La raison pour laquelle nous voulons éviter cela, c'est que la requête One accrochera, puis la demande deux, provoquant la cascade. Si ce n'est pas du tout évitable, nous devrons précharger manuellement les deux requêtes avant de suspendre.
Démo
Voici une démonstration de mon engagement. C'est la même chose que la démo que j'ai liée ci-dessus.
Ouvrez la démo si vous l'exécutez et ouvrez l'outil de développement, assurez-vous de décocher la boîte de cache de désactivation affichée dans l'onglet du réseau Devtools ou vous cassera toute la démo.
Le code est presque le même que celui que j'ai montré auparavant. Une amélioration de la démo est que notre méthode de lecture de cache a les lignes suivantes:
setTimeout (() => Resolve ({}), 7000);
Préchargez bien toutes les images, mais dans la vraie vie, nous ne voulons peut-être pas bloquer le rendu indéfiniment simplement parce qu'une ou deux derrière les images se chargent lentement. Donc, après un certain temps, nous donnons juste le feu vert, même si l'image n'est pas prête. Les utilisateurs verront une image ou deux clignotements, mais c'est mieux que de supporter la frustration de la congélation des logiciels. Je tiens également à souligner que sept secondes peuvent être trop longues, mais pour cette démo, je suppose que les utilisateurs peuvent ralentir le réseau de Devtools pour voir plus clairement les fonctionnalités de suspense et, espérons-le, le supporter.
La démo a également une case d'image précache. Il est sélectionné par défaut, mais vous pouvez le décocher pour utiliser normal<img alt="Images pré-caches avec react suspense" >
Remplacement des balises<suspenseimage></suspenseimage>
Composant, si vous souhaitez comparer la version suspense à "réagir normal" (ne le vérifiez pas lorsque le résultat apparaît, sinon l'interface utilisateur peut accrocher et rendre le repli).
Enfin, comme les codes et boîte, certains états peuvent parfois être hors de synchronisation, donc si les choses commencent à être bizarres ou corrompues, cliquez sur le bouton Actualiser.
Divers
J'ai accidentellement fait une énorme erreur en assemblant cette démo. Je ne veux pas que la démo perde son effet car le navigateur cache l'image qu'il a téléchargée. Je modifie donc manuellement toutes les URL à l'aide d'un disjoncteur de cache:
const [cachebuster, setCacheBuster] = useState (initial_time); const {data} = usUsSpenseQuery (get_images_query, {page}); const images = data.allbooks.books.map ( (b) => b.smallimage `? cachebust = $ {cachebuster}` ));
Initial_time est défini au niveau du module (c'est-à-dire à l'échelle mondiale):
const initial_time = new Date ();
Si vous vous demandez pourquoi je n'ai pas fait ceci:
const [cachebuster, setCacheBuster] = useState (new Date ());
... C'est parce qu'il peut avoir des conséquences terribles et terribles. Lors du premier rendu, l'image tente de rendre. Le cache provoque la suspension, React annule le rendu et affiche notre repli. Lorsque toutes les promesses auront été analysées, React tentera de réinitialiser le rendu et notre premier appel UseState sera réécrit , ce qui signifie:
const [cachebuster, setCacheBuster] = useState (new Date ());
... sera redimensionné avec une nouvelle valeur initiale résultant en un tout nouvel ensemble d'URL d'image, qui accrochera à nouveau indéfiniment. Les composants ne fonctionneront jamais et la démo de codes et de boîte cessera de fonctionner (ce qui rend le débogage frustrant).
Cela semble être un étrange problème spécial causé par les exigences uniques de cette démonstration particulière, mais il y a une leçon plus importante: le rendu devrait être pur et n'a aucun effet secondaire. React devrait être en mesure d'essayer de réintégrer votre composant plusieurs fois et (étant donné le même accessoire initial) doit obtenir le même état exact de l'autre extrémité.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Si vous avez récemment commencé à travailler avec GraphQL ou examiné ses avantages et ses inconvénients, vous avez sans aucun doute entendu des choses comme "GraphQL ne prend pas en charge la mise en cache" ou

Avec la récente montée du prix du bitcoin sur 20k $ USD, et pour lui, récemment en train de briser 30k, je pensais que cela valait la peine de reprendre une profonde plongeon dans la création d'Ethereum

Quelle que soit le stade dans lequel vous vous trouvez en tant que développeur, les tâches que nous effectuons - qu'elles soient grandes ou petites - ont un impact énorme dans notre croissance personnelle et professionnelle.

Il est sorti! Félicitations à l'équipe Vue pour l'avoir fait, je sais que ce fut un effort massif et une longue période à venir. Tous les nouveaux documents aussi.

J'ai eu quelqu'un qui écrivait avec cette question très légitime. Lea vient de bloguer sur la façon dont vous pouvez obtenir les propriétés CSS valides elles-mêmes du navigateur. C'est comme ça.

Je dirais que "Site Web" correspond mieux que "Application mobile" mais j'aime ce cadrage de Max Lynch:

L'autre jour, j'ai repéré ce morceau particulièrement charmant sur le site Web de Corey Ginnivan où une collection de cartes se cassent les uns sur les autres pendant que vous faites défiler.

Il existe un certain nombre de ces applications de bureau où l'objectif montre votre site à différentes dimensions en même temps. Vous pouvez donc, par exemple, écrire
