L'utilisation en componentDidMount()
tant que fonction asynchrone est-elle une bonne pratique dans React Native ou dois-je l'éviter?
J'ai besoin d'obtenir des informations sur AsyncStorage
le montage du composant, mais le seul moyen que je connaisse pour rendre cela possible est de rendre la componentDidMount()
fonction asynchrone.
async componentDidMount() {
let auth = await this.getAuth();
if (auth)
this.checkAuth(auth);
}
Y a-t-il un problème avec cela et y a-t-il d'autres solutions à ce problème?
reactjs
asynchronous
react-native
Mirakurun
la source
la source
Réponses:
Commençons par souligner les différences et déterminer comment cela pourrait causer des problèmes.
Voici le code de la
componentDidMount()
méthode du cycle de vie async et "sync" :En regardant le code, je peux souligner les différences suivantes:
async
mots-clés: en texte dactylographié, il ne s'agit que d'un marqueur de code. Il fait 2 choses:Promise<void>
au lieu devoid
. Si vous spécifiez explicitement que le type de retour n'est pas promis (ex: void), le tapuscript vous crachera une erreur.await
mots-clés dans la méthode.void
àPromise<void>
async someMethod(): Promise<void> { await componentDidMount(); }
Vous pouvez maintenant utiliser le
await
mot-clé dans la méthode et suspendre temporairement son exécution. Comme ça:Maintenant, comment pourraient-ils causer des problèmes?
async
mot-clé est absolument inoffensif.Je ne peux imaginer aucune situation dans laquelle vous devez effectuer un appel à la
componentDidMount()
méthode afin que le type de retourPromise<void>
soit également inoffensif.L'appel à une méthode dont le type de retour est
Promise<void>
sansawait
mot-clé ne fera aucune différence par rapport à l'appel d'une méthode dont le type de retour estvoid
.Puisqu'il n'y a pas de méthode de cycle de vie après avoir
componentDidMount()
retardé son exécution, cela semble assez sûr. Mais il y a un piège.Disons que ce qui précède
this.setState({users, questions});
serait exécuté après 10 secondes. Au milieu du temps d'attente, un autre ...this.setState({users: newerUsers, questions: newerQuestions});
... ont été exécutés avec succès et le DOM a été mis à jour. Le résultat était visible pour les utilisateurs. L'horloge a continué à tourner et 10 secondes se sont écoulées. Le retard
this.setState(...)
s'exécuterait alors et le DOM serait à nouveau mis à jour, cette fois avec d'anciens utilisateurs et d'anciennes questions. Le résultat serait également visible pour les utilisateurs.=> Il est assez sûr (je ne suis pas sûr à 100%) à utiliser
async
avec lacomponentDidMount()
méthode. J'en suis un grand fan et jusqu'à présent je n'ai rencontré aucun problème qui me donne trop de maux de tête.la source
setState()
comporte toujours un petit risque. Nous devons procéder avec prudence.isFetching: true
intérieur de l'état d'un composant. Je n'ai utilisé cela qu'avec redux, mais je suppose que c'est tout à fait valide avec la gestion de l'état de réaction uniquement. Bien que cela ne résout pas vraiment le problème de la mise à jour du même état ailleurs dans le code ...isFetching
solution de drapeau est assez courante surtout lorsque nous voulons jouer certaines animations en front-end en attendant la réponse du back-end (isFetching: true
).Mise à jour d'avril 2020: Le problème semble être résolu dans la dernière React 16.13.1, voir cet exemple de bac à sable . Merci à @abernier pour l'avoir signalé.
J'ai fait quelques recherches et j'ai trouvé une différence importante: React ne traite pas les erreurs des méthodes de cycle de vie asynchrones.
Donc, si vous écrivez quelque chose comme ceci:
alors votre erreur sera interceptée par la limite d'erreur , et vous pouvez la traiter et afficher un message gracieux.
Si nous changeons le code comme ceci:
ce qui équivaut à ceci:
alors votre erreur sera avalée en silence . Honte à toi, réagis ...
Alors, comment traitons-nous les erreurs? Le seul moyen semble être une capture explicite comme celle-ci:
ou comme ça:
Si nous voulons toujours que notre erreur atteigne la limite d'erreur, je peux penser à l'astuce suivante:
render
méthodeExemple:
la source
Votre code est bon et très lisible pour moi. Voir cet article de Dale Jefferson où il montre un
componentDidMount
exemple asynchrone et a l'air vraiment bien aussi.Mais certaines personnes diraient qu'une personne lisant le code peut supposer que React fait quelque chose avec la promesse retournée.
Donc, l'interprétation de ce code et s'il s'agit d'une bonne pratique ou non est très personnelle.
Si vous voulez une autre solution, vous pouvez utiliser des promesses . Par exemple:
la source
async
fonction en ligne avecawait
s à l'intérieur ...?(async () => { const data = await fetch('foo'); const result = await submitRequest({data}); console.log(result) })()
wherefetch
etsubmitRequest
sont des fonctions qui renvoient des promesses.Lorsque vous utilisez
componentDidMount
sansasync
mot-clé, le doc dit ceci:Si vous utilisez,
async componentDidMount
vous perdrez cette capacité: un autre rendu se produira APRÈS la mise à jour de l'écran par le navigateur. Mais imo, si vous songez à utiliser async, comme la récupération de données, vous ne pouvez pas éviter que le navigateur mette à jour l'écran deux fois. Dans un autre monde, il n'est pas possible de PAUSE componentDidMount avant que le navigateur ne mette à jour l'écranla source
Mettre à jour:
(Ma version: React 16, Webpack 4, Babel 7):
En utilisant Babel 7, vous découvrirez:
Utilisation de ce modèle ...
vous rencontrerez l'erreur suivante ...
Uncaught ReferenceError: regeneratorRuntime n'est pas défini
Dans ce cas, vous devrez installer babel-plugin-transform-runtime
https://babeljs.io/docs/en/babel-plugin-transform-runtime.html
Si pour une raison quelconque vous ne souhaitez pas installer le package ci-dessus (babel-plugin-transform-runtime), vous voudrez vous en tenir au modèle Promise ...
la source
Je pense que ça va tant que tu sais ce que tu fais. Mais cela peut être déroutant car il
async componentDidMount()
peut toujours être en cours d'exécution après l'componentWillUnmount
exécution et le démontage du composant.Vous pouvez également démarrer des tâches synchrones et asynchrones à l'intérieur
componentDidMount
. SicomponentDidMount
était asynchrone, vous auriez à mettre tout le code synchrone avant le premierawait
. Il n'est peut-être pas évident pour quelqu'un que le code avant le premierawait
s'exécute de manière synchrone. Dans ce cas, je resterais probablementcomponentDidMount
synchrone, mais je lui ferais appeler les méthodes de synchronisation et d'asynchronisation.Que vous choisissiez les méthodes d' appel
async componentDidMount()
vs sync , vous devez vous assurer de nettoyer tous les écouteurs ou méthodes asynchrones qui peuvent encore être en cours d'exécution lorsque le composant est démonté.componentDidMount()
async
la source
En fait, le chargement asynchrone dans ComponentDidMount est un modèle de conception recommandé car React s'éloigne des méthodes de cycle de vie héritées (componentWillMount, componentWillReceiveProps, componentWillUpdate) et passe au rendu asynchrone.
Cet article de blog est très utile pour expliquer pourquoi cela est sûr et fournir des exemples de chargement asynchrone dans ComponentDidMount:
https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
la source
J'aime utiliser quelque chose comme ça
la source