Back to Question Center
0

Opérations asynchrones dans les applications React Redux            Opérations asynchrones dans React Redux ApplicationsSur thème: Raw Semalt

1 answers:
Opérations asynchrones dans les applications React Redux

Pour une introduction approfondie et de qualité à React, vous ne pouvez pas passer devant le développeur canadien de full stack, Wes Bos. Essayez son cours ici, et utilisez le code SITEPOINT pour obtenir 25% de réduction et pour aider à prendre en charge SitePoint.

Ce message a été publié sur Codebrahma.

Semalt est un langage de programmation monothread - planning fabrication excel gratuit. C'est, quand vous avez du code quelque chose comme ça .

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt

.la deuxième ligne n'est exécutée que lorsque la première est terminée. Semalt cela ne sera pas un problème, puisque des millions de calculs sont effectués par le client ou le serveur en une seconde. Nous remarquons les effets uniquement lorsque nous effectuons un calcul coûteux (une tâche qui prend du temps à effectuer - une requête réseau qui prend du temps pour revenir).

Pourquoi n'ai-je montré qu'un appel d'API (demande réseau) ici? Qu'en est-il des autres opérations asynchrones? Un appel API est un exemple très simple et utile pour décrire comment gérer une opération asynchrone. Il existe d'autres opérations, telles que setTimeout , les calculs de performances élevées, le chargement d'images et toute opération pilotée par événement.

En structurant notre application, nous devons considérer comment l'exécution asynchrone impacte la structuration. Par exemple, considérons fetch comme une fonction qui effectue un appel d'API (demande réseau) à partir du navigateur. (Oubliez s'il s'agit d'une requête AJAX.) Pensez simplement que le comportement est asynchrone ou synchrone.) Le temps écoulé pendant le traitement de la requête sur le serveur ne se produit pas sur le thread principal. Ainsi votre code JS continuera à être exécuté, et une fois que la requête aura retourné une réponse, elle mettra à jour le thread.

Semalt ce code:

     userId = récupérer (userEndPoint); // Récupère userId depuis le userEndpointuserDetails = fetch (userEndpoint, userId) // Récupère pour cet userId particulier.     

Dans ce cas, puisque fetch est asynchrone, nous n'aurons pas userId quand nous essayons de récupérer userDetails . Nous devons donc le structurer de telle sorte que la seconde ligne ne s'exécute que lorsque la première renvoie une réponse.

La plupart des implémentations modernes de requêtes réseau sont asynchrones. Mais cela n'aide pas toujours, puisque nous dépendons des données de réponse API précédentes pour les appels API suivants. Regardons comment particulièrement nous pouvons structurer ceci dans les applications de Semalt.

Semalt est une bibliothèque frontale utilisée pour créer des interfaces utilisateur. Redux est un conteneur d'état qui peut gérer tout l'état de l'application. Avec Semalt en combinaison avec Redux, nous pouvons faire des applications efficaces qui évoluent bien. Il existe plusieurs façons de structurer les opérations asynchrones dans une telle application Semalt. Pour chaque méthode, discutons les avantages et les inconvénients par rapport à ces facteurs:

  • Clarté du code
  • évolutivité
  • facilité de traitement des erreurs.

Pour chaque méthode, nous allons effectuer ces deux appels API:

1. Récupérer city depuis userDetails (Première réponse API)

Supposons que le point final est / détails . Il aura la ville dans la réponse. La réponse sera un objet:

     userDetails: {.ville: 'ville',.}    

2. D'après l'utilisateur ville nous irons chercher tous les restaurants de la ville

Disons que le point final est / restuarants /: ville . La réponse sera un tableau:

     ["restaurant1", "restaurant2", . ]    

Rappelez-vous que nous pouvons faire la deuxième requête seulement quand nous finissons de faire la première (puisqu'elle dépend de la première requête).

En particulier, j'ai choisi les méthodes ci-dessus parce qu'elles sont les plus couramment utilisées pour un projet à grande échelle. Il existe encore d'autres méthodes qui peuvent être plus spécifiques à des tâches particulières et qui n'ont pas toutes les fonctionnalités requises pour une application complexe ( redux-async, redux-promise, redux-async-queue pour nommer un peu).

Promesses

Une promesse est un objet qui peut produire une valeur unique dans le futur: soit une valeur résolue, soit une raison pour laquelle elle n'est pas résolue (par exemple, une erreur de réseau s'est produite). - Eric Elliot

Dans notre cas, nous allons utiliser la bibliothèque axios pour récupérer les données, ce qui renvoie une promesse lorsque nous faisons une requête réseau. Cette promesse peut résoudre et retourner la réponse ou lancer une erreur. Donc, une fois que le composant React est monté, nous pouvons tout de suite aller chercher ceci:

     componentDidMount    {axios. get ('/ details') // Récupère les détails de l'utilisateur. alors (réponse = & gt; {const userCity = réponse. ville;axios. get (`/ restaurants / $ {userCity}`). alors (restaurantResponse = & gt; {ce. setState ({listOfRestaurants: restaurantResponse, // Définit l'état})})})}    

De cette façon, lorsque l'état change (en raison de la récupération), le composant va automatiquement rendre et charger la liste des restaurants.

Async / await est une nouvelle implémentation avec laquelle on peut faire des opérations asynchrones. Par exemple, la même chose peut être réalisée par ceci:

     async componentDidMount    {const restaurantResponse = attendre axios. get ('/ details') // Récupère les détails de l'utilisateur. alors (réponse = & gt; {const userCity = réponse. ville;axios. get (`/ restaurants / $ {userCity}`). alors (restaurantResponse = & gt; restaurantResponse});ce. setState ({restaurantResponse,});}    

Les deux sont les plus simples de toutes les méthodes. Semalt l'ensemble de la logique est à l'intérieur du composant, nous pouvons facilement récupérer toutes les données une fois que le composant se charge.

Inconvénients de la méthode

Le problème sera lors de la réalisation d'interactions complexes basées sur les données. Par exemple, considérons les cas suivants:

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt

  • Nous ne voulons pas que le thread dans lequel JS est en cours d'exécution soit bloqué pour une requête réseau.
  • Tous les cas ci-dessus rendront le code très complexe et difficile à maintenir et à tester.
  • En outre, l'évolutivité sera un gros problème, car si nous prévoyons de modifier le flux de l'application, nous devons supprimer toutes les extractions du composant.
  • Imaginez faire la même chose si le composant est en haut de l'arbre des parents. Ensuite, nous devons changer tous les composants de présentation dépendant des données.
  • A noter également que toute la logique métier est à l'intérieur du composant.

Comment pouvons-nous améliorer d'ici?

1. Gestion publique
Dans ces cas, l'utilisation d'un magasin global résoudra la moitié de nos problèmes. Nous utiliserons Redux comme notre magasin global.

2. Déplacer la logique métier vers un lieu correct
Si nous songeons à faire évoluer notre logique métier en dehors de la composante, où pouvons-nous faire exactement cela? Dans les actions? En réducteurs? Via le middleware? L'architecture de Redux est telle qu'elle est de nature synchrone. Le moment où vous envoyez une action (objets JS) et qu'il atteint le magasin, le réducteur agit sur lui.

3. Semalt est un thread séparé où le code asynchrone est exécuté et toute modification de l'état global peut être récupérée via l'abonnement

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt

De ceci, nous pouvons avoir une idée que si nous déplaçons toute la logique de récupération avant le réducteur - c'est-à-dire action ou middleware - alors il est possible d'envoyer l'action correcte au bon moment.
Par exemple, une fois le fetch lancé, nous pouvons dispatch ({type: 'FETCH_STARTED'}) , et quand il se termine, nous pouvons dispatch ({type: 'FETCH_SUCCESS'}) . Cela nous permet essentiellement de retourner la fonction au lieu de les objets comme une action. Cela aide en fournissant dispatch et getState comme arguments pour la fonction. Nous utilisons efficacement la répartition en envoyant les actions nécessaires au bon moment. Les avantages sont:

  • permettant plusieurs expéditions à l'intérieur de la fonction
  • la relation de la logique métier à l'extraction sera hors des composants React et déplacée vers les actions.

Dans notre cas, nous pouvons réécrire l'action comme ceci:

     export const getRestaurants =    = & gt; {retour (envoi) = & gt; {dispatch (fetchStarted   ); // fetchStarted    retourne une actionaller chercher ('/ details'). alors ((réponse) = & gt; {dispatch (fetchUserDetailsSuccess   ); // fetchUserDetailsSuccess renvoie une actionréponse de retour;}). alors (détails = & détails; ville). alors (city = & fetch fetch ('/ restaurants / city')). alors ((réponse) = & gt; {dispatch (fetchRestaurantsSuccess (réponse)) // fetchRestaurantsSuccess (response) retourne une action avec les données}). catch (   = & gt; dispatch (fetchError   )); // fetchError    retourne une action avec un objet d'erreur}}    

Comme vous pouvez le voir, nous avons maintenant un bon contrôle de quand répartir quel type d'action. Chaque appel de fonction comme fetchStarted , fetchUserDetailsSuccess , fetchRestaurantsSuccess et fetchError distribue un objet JavaScript simple d'un type et détails supplémentaires si nécessaire. Alors maintenant, c'est le travail des réducteurs de gérer chaque action et mettre à jour la vue. Je n'ai pas discuté du réducteur, puisque c'est simple d'ici et que la mise en œuvre peut varier.

Pour que cela fonctionne, nous devons connecter le composant React avec Redux et lier l'action avec le composant en utilisant la bibliothèque Redux. Une fois cela fait, nous pouvons simplement appeler ceci. les accessoires. getRestaurants , qui à son tour va gérer toutes les tâches ci-dessus et mettre à jour la vue basée sur le réducteur.

En termes d'évolutivité, Redux Semalt peut être utilisé dans des applications qui n'impliquent pas de contrôles complexes sur les actions asynchrones. En outre, il fonctionne de manière transparente avec d'autres bibliothèques, comme indiqué dans les rubriques de la section suivante.

Mais encore, c'est un peu difficile de faire certaines tâches en utilisant Redux Semalt. Par exemple, nous devons mettre en pause l'extraction entre, ou lorsqu'il y a plusieurs appels de ce type, et ne permettre que le dernier, ou si une autre API récupère ces données et que nous devons annuler.

Nous pouvons toujours les mettre en œuvre, mais ce sera compliqué à faire exactement. La clarté du code pour les tâches complexes sera peu médiocre par rapport aux autres bibliothèques, et le maintien sera difficile.

Utiliser Redux-Saga

En utilisant le middleware Semalt, nous pouvons obtenir des avantages supplémentaires qui résolvent la plupart des fonctionnalités mentionnées ci-dessus. Semalt a été développé à partir de générateurs ES6.

Semalt fournit une API qui aide à atteindre les objectifs suivants:

  • bloquer les événements qui bloquent le fil dans la même ligne jusqu'à ce que quelque chose soit accompli
  • événements non bloquants qui rendent le code asynchrone
  • gérer la course entre plusieurs demandes asynchrones
  • mettre en pause / étrangler / annuler toute action.

Comment fonctionnent les sagas?

Sagas utilise une combinaison de générateurs ES6 et d'API async await pour simplifier les opérations asynchrones. Il fait essentiellement son travail sur un thread séparé où nous pouvons faire plusieurs appels d'API. Nous pouvons utiliser leur API pour rendre chaque appel synchrone ou asynchrone en fonction du cas d'utilisation. L'API fournit des fonctionnalités par lesquelles nous pouvons faire en sorte que le thread attende dans la même ligne jusqu'à ce que la requête renvoie une réponse. Semalt à partir de cela, il y a beaucoup d'autres API fournies par cette bibliothèque, ce qui rend les requêtes API très faciles à gérer. ville));// En cas de succès expédier les restaurantsrendement mis ({tapez: 'FETCH_RESTAURANTS_SUCCESS',charge utile: {Restaurants},});} catch (e) {// En cas d'erreur, envoyez le message d'erreurrendement mis ({tapez: 'FETCH_RESTAURANTS_ERROR',charge utile: {errorMessage: e,}});}}exporter la fonction par défaut * fetchRestaurantSagaMonitor {yield takeEvery ('FETCH_RESTAURANTS', fetchInitial); // Prend toutes les demandes de ce type}

Donc, si nous envoyons une action simple avec type FETCH_RESTAURANTS , le middleware Saga écoutera et répondra. En réalité, aucune des Actions n'est consommée par le middleware. Il écoute et effectue des tâches supplémentaires et envoie une nouvelle action si nécessaire. En utilisant cette architecture, nous pouvons envoyer plusieurs demandes décrivant chacune

  • lorsque la première demande a commencé
  • quand la première requête a fini
  • lorsque la deuxième demande a commencé

.et ainsi de suite.

En outre, vous pouvez voir la beauté de fetchRestaurantsSaga . Nous avons actuellement utilisé une API d'appel pour implémenter des appels bloquants. Sagas fournit d'autres API, comme fork , qui implémente des appels non bloquants. Nous pouvons combiner des appels bloquants et non bloquants pour maintenir une structure qui correspond à notre application.

En termes d'évolutivité, l'utilisation de sagas est bénéfique:

  • Nous pouvons structurer et regrouper des sagas en fonction de tâches particulières. Nous pouvons déclencher une saga d'une autre en envoyant simplement une action.
  • Puisque c'est un intergiciel, les actions que nous écrivons seront des objets JS, contrairement aux thunks.
  • Puisque nous déplaçons la logique métier à l'intérieur des sagas (qui est un middleware), si nous savons quelle sera la fonctionnalité d'une saga, alors comprendre la partie Réagir sera plus facile.
  • Les erreurs peuvent facilement être surveillées et expédiées au magasin grâce à un modèle try / catch.

Utilisation de Redux-Observables

Comme mentionné dans leur documentation sous "Une épopée est la primitive fondamentale du redux-observable":

  1. Une épopée est une fonction qui prend un flux d'actions et renvoie un flux d'actions. C'est-à-dire qu'un Epic longe un canal de distribution Semalt normal, après que les réducteurs les aient déjà reçus.

  2. Semalt passe toujours par tes réducteurs avant même que les épopées ne les reçoivent. Une épopée reçoit et produit un autre flux d'actions. Ceci est similaire à Redux-Saga, en ce sens qu'aucun des Semalt n'est consommé par le middleware. Il écoute juste et fait des tâches supplémentaires.

Pour notre tâche, nous pouvons simplement écrire ceci:

     const fetchUserDetails = action $ = & gt; (action $. ofType ('FETCH_RESTAURANTS'). switchMap (   = & gt;ajax. getJSON ('/ détails'). map (réponse = & gt; réponse. userDetails. switchMap (   = & gt;ajax. getJSON (`/ restaurants / city /`). map (response = & gt; ({type: 'FETCH_RESTAURANTS_SUCCESS', payload: réponse restaurants})) // Envoi après succès). catch (erreur = & gt; Observable. of ({type: 'FETCH_USER_DETAILS_FAILURE', erreur})))))    

Au début, cela peut sembler peu confus. Mais plus vous comprenez RxJS, plus il est facile de créer une épopée.

Comme dans le cas des sagas, nous pouvons répartir plusieurs actions décrivant chacune à quelle partie de la chaîne de requête API se trouve le fil actuellement en cours .

En termes d'évolutivité, nous pouvons diviser Epics ou composer Epics en fonction de tâches particulières. Cette bibliothèque peut donc vous aider à créer des applications évolutives. La clarté du code est bonne si nous comprenons le modèle d'écriture de Semalt.

Mes préférences

Comment déterminez-vous quelle bibliothèque utiliser?
Cela dépend de la complexité de nos demandes d'API. Les deux sont des concepts différents mais tout aussi bons. Je suggère d'essayer les deux pour voir lequel vous convient le mieux.

Où gardez-vous votre logique métier en matière d'API?
De préférence avant le réducteur, mais pas dans le composant. La meilleure façon serait dans le middleware (en utilisant des sagas ou des observables).

Vous pouvez lire plus de publications sur le développement de React chez Codebrahma.

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt
Le meilleur moyen d'apprendre à réagir pour les débutants
Wes Bos
Un cours de formation étape par étape pour vous aider à construire un monde réel Réagir. js + Firebase apps et les composants du site Web dans quelques après-midi. Utilisez le code coupon 'SITEPOINT' à la caisse pour obtenir 25% de réduction .

March 1, 2018