TL; DR
Comment un composant parent peut-il savoir quand le rendu de chaque composant enfant en dessous est terminé et le DOM visible par l'utilisateur avec sa version la plus récente?
Disons que j'en ai un component A
qui a un Grid
composant enfant composé de 3x3
composants petits - enfants. Chacun de ces composants de petit-enfant récupère les données à partir d'un point de terminaison API reposant et s'affiche lorsque les données deviennent disponibles.
Je voudrais couvrir toute la zone Component A
avec un loader
espace réservé, pour être dévoilé uniquement lorsque le dernier des composants de la grille a récupéré les données avec succès et les a rendues, de sorte qu'elles sont déjà sur le DOM et peuvent être consultées.
L'expérience utilisateur doit être une transition super fluide du «chargeur» vers une grille entièrement peuplée sans scintillement.
Mon problème est de savoir exactement quand dévoiler les composants sous le chargeur.
Existe-t-il un mécanisme sur lequel je peux compter pour le faire avec une précision absolue? Je n'ai pas à coder en dur une limite de temps pour le chargeur. Si je comprends bien, compter sur ComponentDidMount
chaque enfant n'est pas non plus fiable, car cela ne garantit pas réellement que le composant est entièrement visible pour l'utilisateur au moment de l'appel.
Pour distiller encore la question:
J'ai un composant qui rend une sorte de données. Une fois qu'il est initialisé, il ne l'a pas, donc dans son
componentDidMount
il frappe un point de terminaison API pour lui. Une fois qu'il reçoit les données, il change son état pour les refléter. Cela provoque naturellement un nouveau rendu de l'état final de ce composant. Ma question est la suivante: comment savoir quand ce nouveau rendu a eu lieu et se reflète dans le DOM utilisateur. Ce point dans le temps! = Le moment où l'état du composant a changé pour contenir des données.
ComponentDidMount
j'utiliseaxios
pour récupérer des données. lorsque les données arrivent, je change l'état de ce composant qui provoque un rendu des données. En théorie, 8 composants enfants peuvent être récupérés en 3 secondes, et le dernier prendrait 15 secondes ...Réponses:
Il y a deux hooks de cycle de vie dans React qui sont appelés après le rendu DOM d'un composant:
Pour votre cas d' utilisation de votre composant parent P est intéressé lorsque N composants enfants ont chacun satisfait une condition X . X peut être défini comme une séquence:
En combinant l'état du composant et en utilisant le
componentDidUpdate
crochet, vous pouvez savoir quand la séquence est terminée et que votre composant remplit la condition X.Vous pouvez garder une trace de la fin de votre opération asynchrone en définissant une variable d'état. Par exemple:
Après avoir défini l'état, React appellera la
componentDidUpdate
fonction de vos composants . En comparant les objets d'état actuel et précédent dans cette fonction, vous pouvez signaler au composant parent que votre opération asynchrone s'est terminée et que l'état de votre nouveau composant a été rendu:Dans votre composant P, vous pouvez utiliser un compteur pour garder une trace du nombre d'enfants mis à jour de manière significative:
Enfin, en connaissant la longueur de N, vous pouvez savoir quand toutes les mises à jour significatives se sont produites et agir en conséquence dans votre méthode de rendu de P :
la source
Je le configurerais pour que vous vous appuyiez sur une variable d'état globale pour indiquer à vos composants quand effectuer le rendu. Redux est meilleur pour ce scénario où de nombreux composants se parlent et vous avez mentionné dans un commentaire que vous l'utilisez parfois. Je vais donc esquisser une réponse en utilisant Redux.
Il faudrait passer vos appels API au conteneur parent,
Component A
. Si vous souhaitez que vos petits-enfants ne s'affichent qu'après la fin des appels d'API, vous ne pouvez pas conserver ces appels d'API dans les petits-enfants eux-mêmes. Comment faire un appel d'API à partir d'un composant qui n'existe pas encore?Une fois tous les appels d'API effectués, vous pouvez utiliser des actions pour mettre à jour une variable d'état globale contenant un groupe d'objets de données. Chaque fois que des données sont reçues (ou qu'une erreur est détectée), vous pouvez envoyer une action pour vérifier si votre objet de données est entièrement rempli. Une fois complètement remplie, vous pouvez mettre à jour une
loading
variablefalse
et rendre votreGrid
composant sous condition .Ainsi, par exemple:
Votre réducteur contiendra l'objet d'état global qui dira si tout est prêt ou non:
Dans vos actions:
De côté
Si vous êtes vraiment marié à l'idée que vos appels d'API vivent à l'intérieur de chaque petit-enfant, mais que l'ensemble de la grille des petits-enfants ne s'affiche pas tant que tous les appels d'API ne sont pas terminés, vous devrez utiliser une solution complètement différente. Dans ce cas, vos petits-enfants devraient être restitués dès le début pour effectuer leurs appels, mais avec une classe css avec
display: none
, qui ne change qu'après que la variable d'état globalloading
est marquée comme fausse. C'est également faisable, mais en plus du point de React.la source
Vous pouvez potentiellement résoudre ce problème en utilisant React Suspense.
La mise en garde est que ce n'est pas une bonne idée de suspendre au-delà de l'arborescence des composants qui effectue le rendu (c'est-à-dire: si votre composant lance un processus de rendu, ce n'est pas une bonne idée de suspendre ce composant, d'après mon expérience), c'est donc probablement une meilleure idée pour lancer les requêtes dans le composant qui rend les cellules. Quelque chose comme ça:
Maintenant, tout à fait comment Suspense s'associe avec Redux, je ne suis pas sûr. L'idée derrière cette version (expérimentale!) De Suspense est que vous démarrez l'extraction immédiatement pendant le cycle de rendu d'un composant parent et passez un objet qui représente une extraction aux enfants. Cela vous évite d'avoir à avoir une sorte d'objet Barrière (dont vous auriez besoin dans d'autres approches).
Je dirai que je ne pense pas qu'attendre que tout soit allé pour afficher quoi que ce soit soit la bonne approche car alors l'interface utilisateur sera aussi lente que la connexion la plus lente ou peut ne pas fonctionner du tout!
Voici le reste du code manquant:
Et un bac à sable: https://codesandbox.io/s/falling-dust-b8e7s
la source
Tout d'abord, le cycle de vie pourrait avoir une méthode asynchrone / attente.
Ce que nous devons savoir
componentDidMount
etcomponentWillMount
,À mon avis, il suffit de les mettre en œuvre en utilisant un cycle de vie normal.
Material-UI CircularProgress
Étant donné que le rendu de l'enfant oblige le parent à faire de même, l'attraper
didUpdate
serait bien.Et, comme il est appelé après le rendu, les pages ne doivent pas être modifiées après cela si vous définissez la fonction de vérification comme votre demande.
Nous utilisons cette implémentation dans notre prod qui a une api provoquant 30s pour obtenir la réponse, tout fonctionnait bien pour autant que je vois.
la source
Lorsque vous effectuez un appel
componentDidMount
API, lorsque l'appel API sera résolu, vous aurez les données àcomponentDidUpdate
mesure que ce cycle de vie vous passeraprevProps
etprevState
. Vous pouvez donc faire quelque chose comme ci-dessous:Si vous voulez le savoir avant le rendu du composant, vous pouvez l'utiliser
getSnapshotBeforeUpdate
.https://reactjs.org/docs/react-component.html#getsnapshotbeforeupdate .
la source
Il existe plusieurs approches avec lesquelles vous pouvez opter:
la source