[DIY] State Management - React Vs. Vue 🌀

Damien Chazoule
7 min readFeb 5, 2021

--

Les annĂ©es passent, les technologies Ă©voluent, et pourtant certains patterns de dĂ©veloppement restent intacts, voire se bonifient avec le temps
 C’est le cas du State Management !

Introduit avec Flux, une architecture pensĂ©e par Facebook pour Facebook, le State Management est aujourd’hui un incontournable du dĂ©veloppement Web. Ce paradigme de dĂ©veloppement se caractĂ©rise principalement par son flux de donnĂ©es unidirectionnel ; en opposition Ă  la liaison bidirectionnelle de donnĂ©es utilisĂ©e par les frameworks MVW tel qu’AngularJS, ou plus rĂ©cemment Vue. Flux est crĂ©Ă© pour rĂ©soudre certains dĂ©fauts du pattern MVVM (Model-View / View-Model), notamment lors de la montĂ©e Ă  l’échelle d’applications Web. Avec la crĂ©ation du concept de “store”, il n’y a plus (ou en tout cas moins) de problĂšme liĂ© aux diffĂ©rentes sources de donnĂ©es. Tout est alors centralisĂ© au mĂȘme endroit. On dit que le store est unique source de vĂ©ritĂ© !

Tout comme les fonctions callbacks, les promesses ou encore les streams, le State Management est un paradigme de programmation “rĂ©active”. L’idĂ©e d’un tel dĂ©veloppement est que les composants utilisant les donnĂ©es du store, rĂ©agissent lorsque ces mĂȘmes donnĂ©es sont mises Ă  jour. Pour cela, le State Management suit une certaine logique :

  • Le store est en lecture seule
  • Les donnĂ©es sont mises Ă  jour par un “dispatcher”
  • Le dispatcher est sollicitĂ© par des actions
  • L’interface utilisateur dĂ©clenche les actions

Selon les implĂ©mentations de Flux, la notion de “dispatcher” est plus ou moins explicite, cependant le flux de donnĂ©es reste le mĂȘme : la vue dispatche les actions qui mettent Ă  jour les donnĂ©es du store et implicitement mettent Ă  jour les vues associĂ©es Ă  ces donnĂ©es. Dans le monde du dĂ©veloppement Web, il existe beaucoup d’implĂ©mentations diffĂ©rentes de Flux : Fluxxor, MobX, Overmind, etc
 Redux et Vuex sont respectivement les plus connues pour les Ă©cosystĂšmes React et Vue.

Bien que ces dĂ©pendances soient extrĂȘmement pratiques et facilite grandement le travail du dĂ©veloppeur, il est possible de construire soit mĂȘme une architecture de State Management. C’est ce qui nous amĂšne Ă  cet article !

Ci-dessous, nous allons voir comment coder son propre Redux / Vuex, Ă©tapes par Ă©tapes, en utilisant les derniĂšres versions des outils React et Vue actuellement disponibles (version 17 pour la librairie de Facebook, et version 3 pour le framework communautaire).

NB : React utilise les hooks, et Vue utilise l’API Composition. Ces derniĂšres fonctionnalitĂ©s Ă©tant trĂšs similaires, il va ĂȘtre intĂ©ressant de voir comment celles-ci s’interfacent dans ce genre de dĂ©veloppement.

La mise en oeuvre d’un State Management (que ce soit en React ou en Vue) se divise en deux parties :

  • Le Provider qui initialise la mĂ©canique du store
  • Les Consumers qui interagissent avec le store, en lecture et en “dispatchant” les actions

Partie 1 - Le Provider

La crĂ©ation d’un store avec la librairie de Facebook s’effectue grĂące Ă  la combinaison astucieuse des hooks et de l’API Context. La crĂ©ation d’un contexte nous permet d’avoir accĂšs au composant <Provider /> qui se chargera d’intĂ©grer les donnĂ©es du store fournies par le hook useReducer(). En effet, le pattern de dĂ©veloppement “State - Reducer” occupe une place importante dans la gestion d’un Ă©tat complexe d’un composant.

StateProvider.jsx

Ces quelques lignes suffisent Ă  instaurer une mĂ©canique de store. Cependant, afin de rĂ©pandre les donnĂ©es (issues d’un contexte) aux composants enfants, il faut encore encapsuler ces mĂȘmes composants par le composant parent (<StateProvider />), de prĂ©fĂ©rence au plus haut niveau de l’application.

App.jsx

Pour ce qui est du framework communautaire, grĂące Ă  la version 3 de Vue, l’initialisation du store repose majoritairement sur l’API Composition, ainsi que sur le pattern de dĂ©veloppement “Provide / Inject”. Cette derniĂšre fonctionnalitĂ© (dĂ©jĂ  prĂ©sente dans Vue 2) est trĂšs similaire Ă  l’API Context de React, et permet d’étendre des donnĂ©es globales Ă  toute une partie de l’application.

StateProvider.vue

Ci-dessus (les fonctions Ă©tant relativement explicites) on s’aperçoit rapidement que l’on dĂ©clare une variable rĂ©active (l’état global de l’application), puis on la rend disponible, ainsi que les fonctions permettant de la faire muter. Ensuite (et tout comme React), il ne suffit pas d’injecter les donnĂ©es du store dans les composants enfants pour interagir avec ce dernier, il faut Ă©galement “wrapper” ces mĂȘmes composants par le composant parent (<StateProvider /> Ă  nouveau), responsable du store.

App.vue

Partie 2 - Le Consumer

NB : Dans la suite de cet article, les classes CSS que vous retrouverez dans le rendu des composants <StateConsumer /> sont issues d’un framework UI : Bulma !

Une fois le composant enfant encapsulĂ© par le composant garant du store, on rĂ©cupĂšre ses donnĂ©es grĂące Ă  la fonction inject() avec le framework Vue. Le paramĂštre de cette fonction n’est autre qu’un identifiant unique, qui rĂ©fĂšre Ă  la variable / la fonction fourni(e) prĂ©alablement par le composant parent.

StateConsumer.vue

L’option setup() va donc transmettre l’état du store, ainsi que les fonctions permettant de le mettre Ă  jour, au composant fils <StateConsumer /> avant de monter ce dernier. Dans le template ci-dessus, on utilise directement la valeur state.fullName du store, et on la met Ă  jour soit lorsque l’évĂ©nement onchange est dĂ©clenchĂ© par l’<input>, soit lorsque l’évĂ©nement onclick est jouĂ© par le <button>.

Du cĂŽtĂ© de la libraire React, la rĂ©cupĂ©ration des valeurs du store (Ă  savoir son Ă©tat, ainsi que la fonction dispatch()) s’effectue au travers d’un autre hook : useContext(). En important le contexte du store, et en le passant en paramĂštre de cette fonction, un composant “stateless” se “connect” (rĂ©fĂ©rence Ă  Redux) au store de l’application.

StateConsumer.jsx

Reste encore à mettre à jour le store
 Pour cela, il suffit de dispatcher une action. Par convention, une action est un objet disposant de deux propriétés :

  • Le “type” servant de rĂ©fĂ©rence au dispatcher
  • Le “payload” sur lequel le store s’appuie pour mettre Ă  jour son Ă©tat

Hooks Vs. API Composition

L’introduction des hooks avec React 16.8 et l’apparition de l’API Composition de Vue 3, modifient notre façon d’utiliser le store. DĂ©jĂ  prĂ©sente depuis la version 7.1.0 de la dĂ©pendance “React-Redux”, les hooks (useSelector() / useDispatch()) facilitent grandement la “connexion” avec le store, et Ă©vitent une dĂ©marche de HOC (High Order Component), pour passer certaines donnĂ©es d’un composant parent, vers les propriĂ©tĂ©s d’un composant enfant. L’API Composition de Vue, peut-ĂȘtre utilisĂ© de maniĂšre trĂšs similaire aux hooks de React.

hooks/useField.js
composition/useField.js

Cette maniĂšre de faire est de plus en plus rĂ©pandue dans les dĂ©veloppements Web, et rĂ©pond au principe suivant : dĂ©couper pour mieux rĂ©gner ; Parfait pour les applications comptant plus de 100 composants


NB : La convention veut que le nom de ce genre de fonction dĂ©bute par “use” pour prĂ©ciser qu’il s’agit d’une fonction de composition / d’un hook personnalisĂ©.

Ce concept est plutĂŽt intelligent, et permet de penser nos applications plus finement, brique par brique. Cela favorise ainsi la rĂ©usabilitĂ© du code pour les composants ayant la mĂȘme logique : la mĂȘme façon de lire le store et / ou de mettre Ă  jour tout ou partie du store.

StateConsumer.jsx
StateConsumer.vue

NB : L’avantage de la fonction ci-dessus, est qu’elle gĂšre directement la valeur par dĂ©faut du “field” si la valeur de ce dernier n’est pas (encore) prĂ©sente dans le store ; plutĂŽt qu’une gestion dans le template du composant.

Conclusion

J’utilise le State Management depuis plusieurs annĂ©es maintenant, souvent avec Redux (en parallĂšle avec Vuex), j’ai appris Ă  connaĂźtre son fonctionnement et ses nombreux avantages.

Bien qu’extrĂȘmement pratique, le State Management prend tout son sens dans une application Web Ă  l’échelle, avec une multitude de composants, ainsi que de multiples fonctionnalitĂ©s. La centralisation des donnĂ©es, leur lecture et leurs mises Ă  jour deviennent alors plus aisĂ©es.

Les derniĂšres versions des frameworks / librairies JavaScript nous amĂšne Ă  dĂ©composer plus finement nos applications. L’usage des hooks / de l’API Composition rend le State Management plus accessible et clair (plus besoin de dĂ©pendances supplĂ©mentaires mystifiant une partie du code). Il m’arrive donc aujourd’hui d’utiliser cette logique de dĂ©veloppement Ă  plus petite Ă©chelle (pour construire des Single Page Apps avec moins de 50 composants par exemple).

Vous l’aurez compris, je suis assez fan de la programmation rĂ©active par l’usage d’un store. Si vous dĂ©veloppez rĂ©guliĂšrement avec Redux (ou Vuex), ou mĂȘme d’autres librairies (RxJS), je vous invite Ă  faire cet exercice de crĂ©ation d’un State Management from scratch (pour le plaisir du code 😎).

Finalement, cette comparaison entre React et Vue, permet de se rendre compte que ces deux frameworks gravitant autour d’un DOM Virtuel ne sont pas aussi Ă©loignĂ©s l’un de l’autre, malgrĂ© des concepts qui leurs sont propres (tel que la paire “Provide / Inject” de Vue). À la suite de cet article, je pense rĂ©itĂ©rĂ© ce travail sur d’autres outils, surement Svelte dont certaines notions sont assez proches de React et Vue. Cela donnera probablement suite Ă  un article dĂ©rivé 

Sources

Dans le cadre de cet article, j’ai rĂ©alisĂ© deux projets de dĂ©monstration (visuellement identiques) en appliquant l’architecture explicitĂ© prĂ©cĂ©demment. Voici les liens :

--

--

Damien Chazoule

Développeur FullStack passionné d'informatique depuis plus d'une décennie