Débuter avec l'architecture de flux dans React

Ce que vous allez créer

Dans ce didacticiel, vous découvrirez l'architecture Flux de Facebook et son utilisation pour gérer le flux de données dans les applications basées sur React. Nous allons commencer par couvrir les bases de Flux et comprendre la motivation de son développement, puis nous mettrons en pratique ce que nous avons appris en construisant une simple application de portefeuille virtuel..

Tout au long du didacticiel, je suppose que vous avez déjà utilisé React, mais que vous n’avez aucune expérience de Flux. Vous pouvez en tirer quelque chose si vous connaissez déjà les bases de Flux et cherchez à mieux comprendre.

Si vous êtes complètement nouveau sur la scène React, je vous recommande de suivre le cours de mise en route de React de David East, ici sur Envato Tuts +. C'est un parcours fantastique qui vous permettra de vous mettre au diapason en un rien de temps.

Qu'est-ce qu'un flux??

Flux est principalement un concept d'architecture d'application développé par Facebook, mais le même terme se réfère également à une bibliothèque qui représente la mise en œuvre officielle.

Facebook est sorti avec Flux comme une tentative de résoudre les problèmes causés par le modèle MVC dans leur base de code massive. Ils ont dû faire face à des problèmes dans lesquels des actions déclenchaient des mises à jour en cascade conduisant à des résultats imprévisibles et un code difficile à déboguer. Cela peut sembler familier si vous avez déjà utilisé des frameworks MVC, car dans la plupart d'entre eux, tout a tendance à être étroitement couplé. Ajoutez des observateurs et une liaison de données bidirectionnelle au mélange, et vous aurez mal à la tête.

Mon conseil est d'éviter toute tentative de trouver un terrain d'entente entre Flux et MVC. Cela ne vous aidera pas beaucoup, mis à part votre confusion. Flux tente de résoudre les choses différemment, et essayer de les comparer avec d'autres modèles ne va pas aider.

Configuration du projet

Si vous souhaitez suivre le didacticiel, assurez-vous d’abord que le logiciel requis est installé. Lorsque vous avez terminé, clonez le passe-partout branche du dépôt GitHub je me suis préparé à accompagner cet article.

Voici la configuration logicielle requise et les versions que j'avais installées au moment de la rédaction de cet article:

  • Git: 2.11
  • Node.js: 6.9
  • NPM: 3.10
  • Fil: 0,22
  • Votre éditeur de choix

Le passe-partout sert de point de départ au prochain petit projet que nous allons construire, une petite application de portefeuille virtuel. Il contient la configuration Webpack pour transpiler la syntaxe ES6 en JavaScript et en WDS pour le traitement des fichiers. Il possède également des styles de composants CSS pour vous permettre de passer directement au codage..

Afin d'installer toutes les dépendances requises, CD dans le répertoire du projet et exécutez fil.

Dans la section suivante, vous allez configurer les composants principaux de l'application avant d'intégrer Flux. Je ne les ai pas inclus dans le passe-partout car je pense que cela créerait plus de confusion. Si vous ne souhaitez pas créer l'application, vous pouvez ignorer ces étapes et passer à la section suivante..

Configuration des composants

Commencez par inclure le code suivant à l'intérieur js / index.js, qui sert de point d'entrée de l'application:

importer Réagir de 'réagir'; importer ReactDOM de 'react-dom'; importer l'application depuis './components/App'; ReactDOM.render ((), document.getElementById ('app'));

Pour le principal  composant, créer un nouveau fichier à l'intérieur js / composants appelé App.js et ajoutez le code suivant:

importer Réagir de 'réagir'; importer AddNewItem de './AddNewItem'; importer ItemsList de './ItemsList'; La classe App étend React.Component render () return ( 

Portefeuille Flux

) export par défaut App;

le  composant englobe deux autres composants, l'un pour la fiche chargée d'ajouter de nouveaux éléments et l'autre pour la liste d'éléments. Pour créer le composant, créer un nouveau fichier AddNewItem.js à l'intérieur js / composants et ajoutez ce code:

importer Réagir de 'réagir'; class AddNewItem étend React.Component // Définit l'état initial. constructeur (accessoires) super (accessoires); this._getFreshItem = this._getFreshItem.bind (this); this.state = item: this._getFreshItem ();  // Retourne un nouvel élément. _getFreshItem () return description: ", montant:";  // Met à jour l'état. _updateState (event) let field = event.target.name; let value = event.target.value; // Si le montant est modifié et que ce n'est pas un float, retourne. if (valeur && champ === 'montant' &&! valeur.match (/ ^ [a-z0-9. \ + \ -] + $ / g)) return;  this.state.item [field] = valeur; this.setState (item: this.state.item);  // Ajouter un nouvel élément. _addNewItem (event) //… render () return ( 

0 $

$
) export par défaut AddNewItem;

Le composant regroupe une logique pour la mise à jour de l'état lors de la mise à jour des champs de formulaire et une validation de base. Terminons la configuration des composants en créant le dernier à l'intérieur js / components / ItemsList.js pour la liste des articles, en utilisant ce code:

importer Réagir de 'réagir'; class ItemsList étend React.Component constructeur (props) super (props); this.state = items: [];  render () let noItemsMessage; // Affiche un message amical s'il n'y a pas d'éléments. if (! this.state.items.length) noItemsMessage = (
  • Votre portefeuille est neuf!
  • ) revenir (
      noItemsMessage this.state.items.map ((itemDetails) => let amountType = parseFloat (itemDetails.amount)> 0? 'positif': 'negative'; return (
    • itemDetails.description itemDetails.amount
    • ) )
    ) export Default ItemsList;

    C'est tout! Vous avez terminé la configuration des composants du projet. La grande partie est qu'ils viennent aussi avec un style libre.

    Courir début de fil et attendez que le paquet se construise. Si vous pointez votre navigateur sur localhost: 8080, vous devriez voir l'application sans aucune fonctionnalité.

    Nous verrons ensuite ce qu'est Flux et comment vous pouvez l'utiliser pour ajouter des fonctionnalités à l'application de portefeuille virtuel..

    Les composantes du flux

    À un niveau élevé, Flux se décompose en quatre parties principales: actions, répartiteur, magasins et vues:

    • actes décrire une action qui a eu lieu dans l'application.
    • Le répartiteur est un registre de callbacks unique. Il agit en tant qu'intermédiaire en transmettant les actions à tous les magasins qui y ont souscrit..
    • Magasins gérer l'état et la logique nécessaire pour le mettre à jour pour des parties spécifiques de l'application.
    • Des vues sont des vieux composants React simples.

    Dans Flux, toutes les données circulent dans une seule direction:

    • actes sont passés au répartiteur en utilisant des classes de commodité appelées créateurs d'action.
    • Le répartiteur envoie (envoie) les actions à tous les magasins qui y a souscrit.
    • Enfin, si le magasins se soucient d’une action particulière qui a été reçue (ou plus), ils mettent à jour leur état et signalent vues afin qu'ils puissent re-rendre.

    Ci-dessous une représentation visuelle de ce processus.

    actes

    Les données sont envoyées «par le fil» dans une seule direction à l'aide d'objets JavaScript simples appelés actions. Leur travail consiste à décrire un événement qui s'est produit dans l'application et à transférer les nouvelles données dans les magasins. Chaque action doit avoir un type et une clé de charge utile facultative contenant les données. Une action ressemble à celle ci-dessous:

    actionType: "UPDATE_TITLE", charge utile: "Ceci est un nouveau titre." 

    Le type de l'action doit être représenté par une chaîne descriptive et cohérente en majuscule, similaire à la convention habituelle de définition des constantes. Ils servent d'identifiants uniques que les magasins utiliseront pour identifier l'action et réagir en conséquence..

    Une pratique courante consiste à définir tous les types d'action dans un objet constantes et à faire référence à cet objet dans l'application pour maintenir la cohérence. Notre portefeuille virtuel prend en charge une seule action, ce qui ajoute des éléments à la liste. Les dépenses et les gains financiers seront traités comme un seul élément. Notre fichier de constantes sera donc très fin..

    Créé un index.js déposer dans le js / constantes dossier et utilisez le code suivant pour créer votre premier type d’action:

    export par défaut ADD_NEW_ITEM: 'ADD_NEW_ITEM'

    Les actions sont transmises au répartiteur à l'aide d'auxiliaires de classe de confort appelés créateurs d'action qui gèrent la tâche simple de créer et d’envoyer l’action au répartiteur. Avant de créer notre créateur d'action, voyons ce que fait le répartiteur en premier et comprenons son rôle dans Flux.

    Le répartiteur

    Le répartiteur est utilisé pour coordonner la communication entre les créateurs d’action et les magasins. Vous pouvez l'utiliser pour enregistrer le rappel du gestionnaire d'actions d'un magasin et également pour envoyer des actions aux magasins auxquels vous êtes abonné..

    L'API du répartiteur est simple et il ne dispose que de cinq méthodes:

    • registre(): Enregistre le rappel du gestionnaire d'actions d'un magasin.
    • désinscrire () : Annule le rappel d'un magasin.
    • attendre(): Attend que les rappels spécifiés soient exécutés en premier.
    • envoi(): Envoie une action.
    • isDispatching (): Vérifie si le répartiteur envoie actuellement une action.

    Les plus importants sont registre() et envoi() car ils sont utilisés pour gérer la plupart des fonctionnalités de base. Voyons à quoi ils ressemblent et travaillent en coulisse.

    laissez _callbacks = []; class Dispatcher // Enregistre un rappel de magasin. register (callback) let id = 'callback_' + _callbacks.length; _callbacks [id] = callback; id de retour;  // Envoie une action. dispatch (action) for (var id dans _callbacks) _callbacks [id] (action); 

    Ceci est, bien sûr, l'essentiel. le registre() méthode stocke tous les rappels dans un privé _callbacks tableau et envoi() itère et appelle chaque rappel stocké en utilisant l'action reçue.

    Pour des raisons de simplicité, nous n'écrirons pas notre propre répartiteur. Au lieu de cela, nous utiliserons celui fourni dans la bibliothèque de Facebook. Je vous encourage à consulter le dépôt GitHub de Facebook et à voir comment il est mis en œuvre..

    À l'intérieur de js / dispatcher dossier, créer un nouveau fichier index.js et ajoutez cet extrait de code:

    importer Dispatcher de 'flux'; exporter par défaut new Dispatcher ();

    Il importe le répartiteur de la flux bibliothèque qui a été installée en utilisant un fil auparavant et exporte ensuite une nouvelle instance de celle-ci.

    Lorsque le répartiteur est prêt, nous pouvons revenir aux actions et configurer le créateur d'actions de notre application. À l'intérieur de js / actions dossier, créez un nouveau fichier appelé walletActions.js et ajoutez le code suivant:

    importer Dispatcher de '… / dispatcher'; importer des ActionTypes à partir de '… / constantes'; class WalletActions addNewItem (item) // Remarque: il s'agit généralement d'un bon endroit pour effectuer des appels d'API. Dispatcher.dispatch (actionType: ActionTypes.ADD_NEW_ITEM, charge utile: item);  export par défaut new WalletActions ();

    le WalletActions la classe expose un Ajoute un nouvel objet() méthode qui gère trois tâches de base:

    • Il reçoit un article comme argument.
    • Il utilise le répartiteur pour envoyer une action avec le AJOUTE UN NOUVEL OBJET type d'action que nous avons créé plus tôt.
    • Il envoie ensuite le reçu article comme charge utile avec le type d'action.

    Avant de mettre ce créateur d'action à utiliser, voyons quels sont les magasins et comment ils s'intègrent dans notre application alimentée par Flux.

    Magasins

    Je sais, j’ai dit que vous ne devriez pas comparer Flux avec d’autres modèles, mais les magasins Flux ressemblent aux modèles de MVC. Leur rôle est de gérer la logique et de stocker l'état d'un composant de niveau supérieur particulier dans votre application..

    Tous les magasins Flux doivent définir une méthode de gestionnaire d’actions qui sera ensuite enregistrée auprès du répartiteur. Cette fonction de rappel consiste principalement en une instruction switch sur le type d'action reçu. Si un type d'action spécifique est rencontré, il agit en conséquence et met à jour l'état local. Enfin, le magasin diffuse un événement pour signaler les points de vue sur l'état mis à jour afin qu'ils puissent se mettre à jour en conséquence..

    Pour pouvoir diffuser des événements, les magasins doivent étendre la logique d'un émetteur d'événements. Il existe différentes bibliothèques d'émetteur d'événements disponibles, mais la solution la plus courante consiste à utiliser l'émetteur d'événements de Node. Pour une application simple comme un portefeuille virtuel, il n'est pas nécessaire d'avoir plus d'un magasin..

    À l'intérieur de js / magasins dossier, créez un nouveau fichier appelé walletStore.js et ajoutez le code suivant pour la boutique de notre application:

    importer EventEmitter de 'events'; importer Dispatcher de '… / dispatcher'; importer des ActionTypes à partir de '… / constantes'; const CHANGE = 'CHANGE'; let _walletState = []; la classe WalletStore étend EventEmitter constructor () super (); // Enregistre le gestionnaire d'actions avec le répartiteur. Dispatcher.register (this._registerToActions.bind (this));  // Bascule sur le type de l'action lorsqu'une action est distribuée. _registerToActions (action) switch (action.actionType) case ActionTypes.ADD_NEW_ITEM: this._addNewItem (action.payload); Pause;  // Ajoute un nouvel élément à la liste et émet un événement CHANGED. _addNewItem (item) item.id = _walletState.length; _walletState.push (item); this.emit (CHANGE);  // Retourne l'état du magasin actuel. getAllItems () return _walletState;  // Calculez le budget total. getTotalBudget () let totalBudget = 0; _walletState.forEach ((item) => totalBudget + = parseFloat (item.amount);); renvoyer totalBudget;  // Attache le rappel d'un composant React à l'événement CHANGED. addChangeListener (rappel) this.on (CHANGE, rappel);  // Supprime le programme d'écoute de l'événement CHANGED. removeChangeListener (rappel) this.removeListener (CHANGE, rappel);  export par défaut nouveau WalletStore ();

    Nous commençons par importer les dépendances requises pour le magasin, en commençant par l'émetteur d'événements du nœud, le répartiteur suivi des ActionTypes. Vous remarquerez qu'en dessous, il y a une constante CHANGEMENT, semblable aux types d'action que vous avez appris plus tôt. 

    En fait, ce n'est pas un, et il ne faut pas confondre. C'est une constante utilisée pour le déclencheur d'événement lorsque les données du magasin changent. Nous allons le garder dans ce fichier car ce n'est pas une valeur utilisée dans d'autres parties de l'application.

    Une fois initialisé, le WalletStore classe commence par enregistrer le _registerToAction () rappel avec le répartiteur. En coulisse, ce rappel sera ajouté à la liste de contrôle du répartiteur. _callbacks tableau. 

    La méthode a un seul commutateur déclaration sur le type d'action reçu du répartiteur lorsqu'une action est envoyée. Si cela répond à la AJOUTE UN NOUVEL OBJET type d'action, il exécute ensuite le _Ajoute un nouvel objet() méthode et passe le long de la charge utile reçue.

    le _Ajoute un nouvel objet() fonction définit un identifiant pour l'élément, le pousse vers la liste des éléments existants, puis émet un CHANGEMENT un événement. Ensuite, le getAllItems () et getTotalBudget () les méthodes sont des accesseurs de base que nous utiliserons pour récupérer l'état du magasin actuel et le budget total.

    Les deux dernières méthodes, addChangeListener () et removeChangeListener (), sera utilisé pour relier les composants React au WalletStore afin qu'ils soient avertis lorsque les données du magasin changent.

    Vues du contrôleur

    L'utilisation de React nous permet de décomposer des parties de l'application en divers composants. Nous pouvons les imbriquer et construire des hiérarchies intéressantes qui forment des éléments de travail dans notre page..

    Dans Flux, les composants situés en haut de la chaîne ont tendance à stocker la plupart de la logique nécessaire pour générer des actions et recevoir de nouvelles données. par conséquent, elles s'appellent des vues de contrôleur. Ces vues sont directement connectées aux magasins et sont à l'écoute des événements de changement déclenchés lors de la mise à jour des magasins..

    Lorsque cela se produit, les vues du contrôleur appellent le setState méthode qui déclenche la rendre() méthode pour exécuter et mettre à jour la vue et envoyer des données aux composants enfants via des accessoires. À partir de là, React et le DOM virtuel font leur magie et mettent à jour le DOM aussi efficacement que possible..

    Notre application est assez simple et ne respecte pas cette règle du livre. Toutefois, en fonction de la complexité, les applications plus volumineuses peuvent parfois nécessiter plusieurs vues de contrôleur avec des sous-composants imbriqués pour les principales parties de l'application..

    Le bien ensemble

    Nous avons terminé de couvrir les principales parties de Flux, mais l'application de portefeuille virtuel n'est pas encore terminée. Dans cette dernière section, nous allons passer en revue le flux complet des actions aux vues et compléter le code manquant nécessaire pour compléter le flux de données unidirectionnel de Flux..

    Envoi d'une action

    Revenir à la composant, vous pouvez maintenant inclure le WalletActions module et l'utiliser pour générer une nouvelle action dans le _Ajoute un nouvel objet() méthode.

    importer Réagir de 'réagir'; importer WalletActions à partir de '… / actions / walletActions'; //… _addNewItem (event) event.preventDefault (); this.state.item.description = this.state.item.description || '-'; this.state.item.amount = this.state.item.amount || "0"; WalletActions.addNewItem (this.state.item); this.setState (item: this._getFreshItem ());  //… 

    Désormais, lorsque le formulaire est soumis, une action est envoyée et tous les magasins, un dans notre cas, sont informés des nouvelles données..

    Écoute des changements de magasin

    Dans ton WalletStore, actuellement, lorsqu'un élément est ajouté à la liste, son état change et le CHANGEMENT L'événement est déclenché, mais personne n'écoute. Fermons la boucle en ajoutant un écouteur de changement à l'intérieur du composant.

    importer Réagir de 'réagir'; importer WalletStore à partir de '… / stores / walletStore'; class ItemsList étend React.Component constructeur (props) super (props); this.state = items: WalletStore.getAllItems (); this._onChange = this._onChange.bind (this);  _onChange () this.setState (items: WalletStore.getAllItems ());  composantWillMount () WalletStore.addChangeListener (this._onChange);  composantWillUnmount () WalletStore.removeChangeListener (this._onChange);  render () //… export par défaut ItemsList;

    Le composant mis à jour ferme le flux de données unidirectionnel de Flux. Notez que j'ai sauté, y compris la totalité rendre() méthode pour économiser de l'espace. Passons en revue les nouveautés:

    • le WalletStore le module est inclus en haut.
    • L'état initial est mis à jour pour utiliser l'état du magasin à la place.
    • Un nouveau _sur le changement() méthode est utilisée pour mettre à jour l'état avec les nouvelles données du magasin.
    • En utilisant les crochets du cycle de vie de React, le _sur le changement() callback est ajouté et supprimé en tant que rappel du programme d'écoute du magasin.

    Conclusion

    Félicitations! Vous avez fini de créer une application de portefeuille virtuel opérationnelle alimentée par Flux. Vous avez appris comment tous les composants de Flux interagissent les uns avec les autres et comment vous pouvez l'ajouter à la structure des applications React..

    Lorsque vous êtes confiant dans vos compétences en Flux, vérifiez également les autres implémentations de Flux telles que Alt, Delorean, Flummox ou Fluxxor et voyez laquelle vous convient le mieux..

    Dites-moi ce que vous pensez dans les commentaires ci-dessous. J'aimerais savoir ce que vous pensez de Flux ou aider si vous rencontrez des difficultés pour suivre ce didacticiel. Si vous le souhaitez, vous pouvez également me joindre sur Twitter @hiskio.