Fermer

avril 19, 2021

Le guide de MobX


Découvrez une fantastique bibliothèque de gestion d'état, MobX, et comment l'utiliser dans vos projets React.

La gestion des états est aujourd'hui un sujet important dans toutes les applications. Lorsque nous commençons à définir le strict minimum de notre application, après avoir défini le framework ou la bibliothèque que nous utiliserons, le prochain sujet à définir est la gestion des états.

Nous devons décider: devons-nous utiliser une bibliothèque de gestion d’états? Lequel devrions-nous utiliser?

Nous savons pertinemment que maintenant, dans React, nous avons beaucoup de solutions pour la gestion des états. Nous pouvons utiliser React Hooks, une fonctionnalité publiée dans la version 16.7 qui nous permet de gérer et de traiter nos données d'état dans des composants fonctionnels, ce qui signifie que nous pouvons arrêter d'utiliser des composants de classe uniquement pour la gestion d'état. Ou, nous pouvons utiliser la bibliothèque qui a été la plus largement utilisée dans la communauté React depuis longtemps, Redux.

Mais il y a une autre bibliothèque, pas aussi célèbre que Redux, qui peut nous aider à gérer nos données d'état, et elle

MobX

MobX est une bibliothèque de gestion d'état simple, évolutive et puissante. Tout comme React, qui utilise un DOM virtuel pour rendre les éléments de l'interface utilisateur dans nos navigateurs, réduisant le nombre de mutations DOM, MobX fait la même chose mais dans notre état d'application.

MobX a été créé en utilisant TFRP (application transparente programmation réactive) . Nous pouvons le comprendre comme étant une bibliothèque réactive: cela rend l'état de notre application cohérent et sans bogue en utilisant un graphe d'état de dépendance réactif qui ne sera mis à jour que lorsque cela sera nécessaire.

Une déclaration qui définit très bien MobX est:

Tout ce qui peut être dérivé de l'état de l'application doit être dérivé. Automatiquement.

MobX a de grandes différences avec Redux. Par exemple, dans Redux, nous ne pouvons avoir qu'un seul magasin dans lequel nous stockons toutes nos données d'état; dans MobX, nous pouvons avoir plusieurs magasins à des fins différentes. Une autre grande différence est que, dans Redux, notre état est immuable, alors que dans MobX nous pouvons muter notre état.

Beaucoup de gens aiment expliquer que MobX traite l'état de votre application comme une feuille de calcul, ce qui est vrai. Un autre avantage de MobX est qu'il s'agit d'une bibliothèque indépendante du framework, ce qui signifie que vous pouvez également l'utiliser dans d'autres environnements JS, ou même dans d'autres langages – par exemple, Flutter.

MobX a quatre concepts principaux que nous devrions apprendre , pour comprendre son fonctionnement: observables valeurs calculées réactions et actions .

 Quatre cases: observable , Calculé, réaction, action. Observable a deux ensembles de flèches:

Observables

Les observables dans MobX nous permettent d'ajouter des capacités observables à nos structures de données – comme des classes, des objets, des tableaux – et de rendre nos propriétés observables. Cela signifie que notre propriété stocke une valeur unique, et chaque fois que la valeur de cette propriété change, MobX gardera une trace de la valeur de la propriété pour nous.

Par exemple, imaginons que nous ayons une variable appelée counter . Nous pouvons facilement créer une observable en utilisant le décorateur @observable comme ceci:

 import   { observable }   from   "mobx"  ]; 
 classe   CounterStore   {
  @observable counter  =   0 
} 

En utilisant le décorateur @observable nous disons à MobX que nous voulons garder une trace de la valeur du compteur et chaque fois que le compteur change, nous obtenons la valeur mise à jour.

Si vous ne souhaitez pas utiliser le décorateur @observable vous pouvez utiliser décorer pour rendre votre objet observable:

 import   { decorate  observable }   from   "mobx"  ; 
 classe   CounterStore   {
  compteur  =   [] 
} 

 décorer  ( CounterStore   {
  compteur :  observable
} ) 

Valeurs calculées

Dans MobX, nous pouvons comprendre les valeurs calculées comme des valeurs qui peuvent être dérivées de notre état, donc le nom «valeurs calculées» a tout son sens. Ce sont essentiellement des fonctions dérivées de notre état, donc chaque fois que notre état change, leurs valeurs de retour changent également.

Une chose dont vous devez vous souvenir à propos des valeurs calculées est que la syntaxe get est requis, et la dérivation qu'il fait de votre état est automatique – vous n'avez rien à faire pour obtenir la valeur mise à jour.

Pour avoir des valeurs calculées, vous pouvez utiliser le décorateur @computed comme ceci:

 import   { observable }   from   "mobx" ; 
 class   CounterStore   {
  @ compteur observable  =   0 
  @computed  get   counterMoreThan100  ()   {
     return   this .  counter >   100 
  } 
} 

Ou, si vous ne voulez pas utiliser le décorateur @computed vous pouvez également utiliser decorate :

 import   { ] observable  calculé }   à partir de   "mobx" ; 
 class   CounterStore   {
  counter  =   0 
     get   counterMoreThan100  ()   {
       return   this .  counter > [19659028] 100 
    } 
} 

 décorer  ( CounterStore   {
  compteur :  observable 
  counterMoreThan100 :  calculé
} ) 

Actions

Les actions dans MobX sont un concept très important car elles sont responsables de la modification de notre état. Ils sont responsables de changer et de modifier nos observables.

Pour créer des actions dans MobX, vous pouvez utiliser le décorateur @action comme ceci:

 import   { observable }   de   "mobx" ; 
 classe   CounterStore   {
  @ compteur observable  =   0 
  @computed  get   counterMoreThan100  ()   {
     return   this .  counter >   100 
  } 
  @action  incrementCounter  ()   {
     return   this .  counter  +   1 
  } 
} 

Réactions

Les réactions dans MobX sont assez similaires aux valeurs calculées, mais la différence est que les réactions déclenchent des effets secondaires et se produisent lorsque nos observables changent. Les réactions dans MobX peuvent être soit des changements d'interface utilisateur, soit des changements d'arrière-plan – par exemple, une requête réseau, une impression sur la console, etc.

Nous avons les réactions personnalisées: autorun reaction ] quand .

Autorun

Autorun s'exécutera chaque fois qu'un changement observable spécifique. Par exemple, si nous voulions imprimer la valeur du compteur à chaque fois qu'il change, nous pourrions faire comme ceci:

 autorun  ( ()   =>   { ]
  console .  log  ( `Compteur remplacé par:  $ { this .  counter } `  [19659024]) 
} ) 

La réaction autorun reçoit un deuxième argument; ce deuxième argument peut être un objet avec les options suivantes:

  • delay : Vous pouvez annuler votre réaction autorun en passant un nombre; si vous ne passez rien, aucun anti-rebond ne se produira.
  • name : Vous pouvez nommer votre réaction d'exécution automatique en passant une chaîne.
  • onError : Vous pouvez passer une fonction pour gérer les erreurs de votre réaction d'exécution automatique.
  • scheduler : Vous pouvez planifier et déterminer si vous souhaitez réexécuter votre fonction d'exécution automatique en la programmant. Il prend une fonction qui devrait être appelée à un moment donné dans le futur, par exemple: {scheduler: run => {setTimeout (run, 1000)}} .

Reaction

La réaction est très similaire à autorun, mais cela vous donne plus de contrôle sur les valeurs des observables à suivre. Il reçoit deux arguments: le premier est une fonction simple pour renvoyer les données à utiliser dans le second argument. Le deuxième argument sera la fonction d'effet; cette fonction d'effet ne réagira qu'aux données qui ont été passées dans le premier argument de fonction. Cette fonction d'effet ne sera déclenchée que lorsque les données que vous avez transmises dans le premier argument auront changé.

 reaction  ( ()   =>  data [19659021] ( data  reaction )   =>   { sideEffect }  options ?  ]) 

Par exemple, créons une réaction pour imprimer dans la console lorsque le compteur est supérieur à 100.

 const  customReactionCounter  =   reaction  (
   ([19659024])   =>  compteur .  longueur >   100 
  counter  =>  console .  log  ( `Counter is:  $ { counter } `  [19659024]) 
) 

La réaction reçoit également un troisième argument, qui peut être un objet avec les options suivantes:

  • fireImmediately : C'est une valeur booléenne et elle indique si la fonction doit être déclenchée après la première exécution de la fonction de données.
  • delay : Vous pouvez annuler votre fonction de réaction en passant un nombre; si vous ne passez rien, aucun anti-rebond ne se produira.
  • est égal à : comparateur.default par défaut. Si elle est spécifiée, cette fonction de comparaison sera utilisée pour comparer les valeurs précédentes et suivantes produites par la fonction data . La fonction effect ne sera appelée que si cette fonction renvoie false. Si spécifié, ceci remplacera compareStructural .
  • name : Vous pouvez nommer votre réaction d'exécution automatique en passant une chaîne.
  • onError : Vous pouvez transmettre une fonction pour gérer les erreurs de votre réaction d'exécution automatique.
  • scheduler : Vous pouvez planifier et déterminer si vous souhaitez réexécuter votre fonction en la programmant.

The when Reaction

Of les trois réactions personnalisées de MobX, lorsque est de loin mon préféré car il est très facile à comprendre lorsque vous apprenez et semble vous donner des super pouvoirs dans votre code.

Le quand réaction est une fonction qui reçoit deux arguments: le premier est un prédicat qui s'exécutera lorsque la valeur renvoyée est vraie, et le second argument est un effet .

 lorsque [19659024] ( prédicat :   ()   =>  booléen  effet ? :   ()   =>   void  options ? ) 

Alors, par exemple, imaginons que nous avons une réaction lorsque dans notre code, et chaque fois que la valeur du compteur est supérieure à 100, nous voulons incrémenter notre compteur. C'est ainsi que nous pouvons faire cela avec la réaction quand :

 classe   CounterStore   {
   constructeur  ()   {
     quand  (
       ()   =>   this .  counterMoreThan100 
       ()   =>   this .  incrementCounter
    ) 
  } 
  @ compteur observable  =   0 
  @computed  get   counterMoreThan100  ()   {
     return   this .  counter >   100 
  } 
  @action  incrementCounter  ()   {
     return   this .  counter  +   1 
  } 
} 

Maintenant que nous avons appris les quatre concepts principaux de MobX, construisons quelque chose pour que nous puissions les appliquer et apprendre comment tout cela fonctionne dans la pratique.

Premiers pas avec MobX

Nous allons créer un simple application que nous pouvons ajouter et supprimer des livres. Créons donc une nouvelle application create-react-app .

 npx create  -  react  -  app mobx  -  exemple

Installons maintenant les deux dépendances dont nous allons avoir besoin pour utiliser MobX: mobx et mobx-react .

 yarn add mobx mobx  -  réagir

Maintenant, nous allons créer notre boutique. Nous allons avoir un observable appelé books qui sera un tableau de livres, et deux actions: addBook et removeBook . N'oubliez pas d'ajouter les décorateurs respectifs: le @observable décorateur pour les livres et le @action décorateur pour nos addBook et removeBook fonctions.

 import   { observable  action }   from   'mobx' ; 
 class   BooksStore [19659021] {
  @ livres observables  =   [] ; 
  @action  addBook   =   ( book )   =>   {
     this .  books .  push  ( livre ) 
  } 
  @action  removeBook   =   ( index )   =>   {
     this .  books .  épissure  ( index   1 ) 
  } 
} 

 export   default  BooksStore

Maintenant que nous avons créé notre boutique, nous devons y avoir accès. Nous allons utiliser le Provider de mobx-react donc dans notre fichier index.js importez simplement le Provider de mobx-react et enveloppez notre composant App comme ceci:

 import   { Provider }   from   'mobx -react '; 
 < Provider booksStore  =  { booksStore } > 
 < App  /  ]> 
 < /  Provider > 

Ce composant Provider fonctionne à peu près comme le fournisseur Redux. Nous avons un magasin et nous pouvons utiliser ce fournisseur pour transmettre des magasins en utilisant le mécanisme de contexte de React.

Maintenant, dans notre composant App importons certaines choses.

 import   { observer  inject }   from   'mobx-react' ; 

Pour injecter ou connecter nos magasins à notre App nous allons utiliser inject . Cela mettra nos magasins (dans notre cas, le booksStore ) à la disposition de notre composant. Nous utiliserons l'observateur pour rendre réactif notre composant App ce qui signifie que ce composant suivra les observables que nous utilisons dans notre rendu et le rendra automatiquement à chaque fois que nos observables (dans notre cas, le tableau des livres) change.

Maintenant, nous allons encapsuler notre composant App avec les deux fonctions, et il ressemblera à ceci:

 const  App  =   inject  ( [ "booksStore" ] )  ( observateur  ( ( {  _booksStore_ } :  _any_ )   =>   {

 ... 

} ) )  ; 

Créons un div et à l'intérieur de ce div nous allons avoir une entrée et un bouton . Nous allons utiliser le hook useState de React pour gérer l'état à l'intérieur de notre composant, juste pour garder une trace de la valeur de l'entrée.

Alors, créons maintenant notre état en utilisant useState et une nouvelle fonction pour ajouter un livre à chaque fois que nous cliquons sur le bouton.

 const   [ newBook ​​ setNewBook ​​]   =   useState  ( '' ) ; 
 const   addNewBook ​​  =   ()   =>   {
   if   (!  newBook ​​)   return ; 
  booksStore .  addBook  ( newBook ​​) ; 
   setNewBook ​​ ( "" ) ; 
} 

Dans notre entrée, nous allons passer le newBook ​​ comme valeur, et une méthode onChange . Dans notre bouton, nous allons ajouter addNewBook ​​ à exécuter chaque fois que nous cliquons sur le bouton.

  < input _type_  =  "text"  ] _value_  =  { newBook ​​}  _onChange_  =  { ( _e_ )   =>   setNewBook ​​ ( e .  target .  value ) }   / > 
 < button _onClick_  =  { addNewBook ​​} >  add  < /  button > 

Nous n'avons aucun livre encore. Mappons maintenant notre tableau books et pour chaque livre, nous allons ajouter un onClick pour supprimer un livre.

  { booksStore  ].  livres .  carte  ( ( _book_  _index_ )   =>   (
   < h1 _key_  =  { index }  _onClick_  =  { ()   =>  booksStore .  removeBook  ( index ) } >  { book }  < /  h1 > 
) ) } 

Notre dernier composant va ressembler à ceci:

 const  App  =   inject  ] ( [ "booksStore" ] )  ( observateur  ( ( { _booksStore_ } [19659024]:  _any_ )   =>   {
   const   [ newBook ​​ setNewBook ​​]   =  useState  < _string_ >  ( '' ) ; 
   const   addNewBook ​​  =   ()   =>   {
     if   (!  newBook ​​)   return ; 
    booksStore .  addBook  ( newBook ​​) ; 
     setNewBook ​​ ( "" ) ; 
  } 

   return   (
     < div > 
     { booksStore .  books .  map  ( ] ( _book_ :  _string_  _index_ :  _number_ )   =>   (
     < h1 _key_  =  { index }  _onClick_  =  { ()   =>  booksStore  .  removeBook  ( index ) } >   { book } 
     < /  h1 > 
  ) ) } 
   < input _type_  =  "text"  _value_  =  { newBook }  _onChange_  =  { ( _e_ :  _any_ )   =>   setNewBook ​​ ( e .  ] cible .  valeur ) }   / > 
   < button _onClick_  =  { addNewBook ​​ } >  add  < /  button > 
   < /  div > 
  ) 
} [19659024]) ) ; 

Nous devrions maintenant avoir un composant simple fonctionnant qui nous permet d'ajouter et de supprimer des livres. Comme vous pouvez le voir, MobX est très simple à démarrer et nous pouvons créer des choses puissantes avec. Si vous envisagez de passer à cette bibliothèque, je vous recommande vraiment de le faire.

Conclusion

Dans cet article, nous avons appris comment MobX fonctionne, y compris en quoi il est différent de Redux, ainsi que ses quatre principaux concepts: observables, valeurs calculées, actions, réactions. Et puis nous avons créé un exemple pour le tester dans la pratique.




Source link

avril 19, 2021 Mobx