introduction fr - HichamBenjelloun/river GitHub Wiki

Introduction

Le framework River est un framework basé sur l'architecture Flux.

Le framework propose les fonctionnalités suivantes:

  • Implémentation de Flux.
  • Classes de base permettant de gérer les services communs.
  • Couche modèle avec fonctionnalités de validation de champs.

Compilation

Le projet est configuré pour compiler le code JavaScript ES6 en Javascript ES5 pour qu'il soit compréhensible par les navigateurs qui ne le supporteraient pas encore.

Pour compiler l'application, il suffit d'exécuter la commande:

gulp build

Cette phase de build produit un dossier build contenant toutes les ressources de l'application, notamment le fichier app.js qui est importé par le fichier index.html.

Remarques:

  • Les options de configuration de la phase de build sont définies dans le fichier gulpfile.js.
  • Pour avoir une version compressée de l'application, faire:
gulp compress

Par défaut, le projet est configurer pour compiler, puis compresser l'application, donc la commande suivante devrait suffire:

gulp

Vous pouvez configurer ce fichier en fonction de vos besoins, l'idée ici est d'avoir une base simple et fonctionnelle pour commencer à développer sans se soucier dans l'immédiat de la configuration.

Description générale d'une application River

Aperçu de la structure de l'application

Structure du répertoire de travail

Le répertoire de travail se présente sous la forme suivante:

  • sources: contient l'ensemble des sources de l'applications. Une source est une classe étendant la classe de base Source et implémentant la méthode fetch(), dont le rôle est de retourner des données.
  • stores: contient l'ensemble des stores de l'application. Un store est une classe étendant la classe de base Store et implémentant la méthode handle() permettant de modifier son état interne en fonction de l'action reçue. C'est là où sont stockées les données localement.
  • models: Contient l'ensemble des modèles de l'application. Ils permettent de décrire la structure des différents objet et de leur attribuer un type et des contraintes utiles pour la validation de formulaire.
  • constants: Contient l'ensemble des constantes décrivants les actions utilisateurs. Ces constantes permettent de donner un nom aux actions utilisateurs qui vont être utilisés par les créateurs d'actions et les stores pour communiquer entre eux via le Dispatcher. Le Dispatcher est un service permettant de diriger les actions vers les fonctions de callback enregistrées par les stores. Ces fonctions de callback correspondent en fait aux méthodes handle() des différents stores, qui sont automatiquement enregistrées auprès du Dispatcher lorsque les stores sont instanciés.
  • actions: Contient l'ensemble des actions utilisateurs. Chaque action se charge d'envoyer une charge utile (un objet contenant des données, appelé payload) à l'ensemble des stores concernés par l'action.
  • components: les composants React. L'état de ces composants et initialisé et mis à jour exclusivement à partir des stores.

Déroulement de l'application et communication entre les composants

Pour comprendre comment ces composants intéragissent entre eux, expliquons ce qui se passe avec l'application Todo. Nous verrons par la suite plus en détail comment écrire chacun des composants de l'application

  • L'utilisateur charge l'application, React réalise le rendu du composant principal (appelé dans index.js).
  • Le composant Todos, lorsqu'il est monté, s'enregistre auprès du TodoStore qui se charge de récupérer les données. Cet enregistrement se déroule dans la méthode componentDidMount():
componentDidMount() {
   TodoStore.addChangeListener(this._onChange.bind(this));
   TodoStore.requestData();
}

Dans la première ligne, on informe TodoStore que la méthode _onChange(), définie dans le composant, doit être appelée à chaque fois que le store est mis à jour (le store notifie cette mise à jour en appelant la méthode emitChange() de Store, comme on le verra par la suite).

Dans la seconde ligne, l'appel de la méthode requestData() permet de récupérer de façon asynchrone les données de la source associée au store. Lorsque la source reçoit cette requête, elle récupère les données puis déclenche une action, ici receiveData() permettant de faire passer les données au store lorsque celui-ci va la gérer dans sa méthode handle().

handle(payload) {
  let action = payload.action;
  switch(action.actionType) {
    case Actions.TODO_RECEIVE_DATA:
      this.fetch(action.data);
      this.setIsLoading(false);
      this.emitChange();
      break;
    // [...]
  }
}

Remarque: Le descripteur Action est en fait un raccourci de TodoConstants défini plus haut dans le fichier pour éviter d'avoir à retaper TodoConstants plusieurs fois.

Une fois que le store récupère les données, il met à jour son état interne et émet un changement. La méthode _onChange() qu'on a vu précedemment est donc logiquement appelée et l'état du composant est mis à jour.

_onChange() {
  this.setState({
    todos: TodoStore.getAll()
  });
}

Dans cette méthode, on précise au composant que que le champs todos de son état (state) doit être mis à jour avec les valeurs retournées par TodoStore.getAll().

En résumé,

  1. Le composant est monté et enregistre une fonction de callback auprès du store. Cette fonction de callback va être utilisée pour mettre à jour l'état du composant.
  2. Le composant demande au store de mettre à jour ses données à partir de sa source à l'aide de la méthode requestData().
  3. La source récupère les données et déclenche envoie une action avec les données récupérées.
  4. La méthode handle() du store est appelée et le store met à jour son état interne en fonction des données récupérées. Il émet une notification de changement à l'aide de la méthode emitChange(). Comme on l'a précisé dans le point 1., la méthode _onChange() du composant est appelée, et la boucle est bouclée!

Vous pouvez lire le code de l'application d'exemple, Todo pour comprendre comment le framework fonctionne, ou lire les prochains tutoriels pour savoir comment développer chaque composant de l'application.