Lorsque l’on travaille avec des frameworks populaires comme React ou Vue, il est nécessaire d’organiser un stockage pratique et de gérer l’état de l’application. Par exemple, React permet de gérer l’état des composants dès l’installation grâce à `this.setState` et `this.state`. Cependant, avec la croissance de l’application, le besoin de communication entre les composants apparaît, ce qui entraîne souvent des fonctionnalités insuffisantes. Heureusement, dans le monde du front-end, il existe de nombreuses bibliothèques prêtes à l’emploi pour simplifier cette tâche. Cet article présente deux des solutions les plus populaires du moment : Redux et MobX.
À propos de Redux et MobX
Actuellement, la bibliothèque la plus populaire pour stocker l’état d’une application est Redux, inventée en 2015 par Dan Abramov et Andrew Clark. Elle est basée sur l’architecture Flux et la programmation fonctionnelle. Les utilisateurs de Redux bénéficient du soutien d’une communauté solide et d’une riche base de code, ce qui fait que toute question concernant la bibliothèque trouve rapidement une réponse.
L’alternative la plus répandue est MobX, inventée par Michel Weststrate en 2015. Elle est implémentée selon les principes de la programmation réactive fonctionnelle (FRP) et permet d’encapsuler les états dans des objets « observables ». Cela facilite la réaction à tout changement d’état de l’application.
Flux de données et principales différences
Redux :

- Possède un seul store comme source unique de vérité. L’état est stocké dans un objet JavaScript ordinaire. Il est préférable de garder l’état normalisé et plat.
- L’état est immuable. Toute mise à jour de l’état renvoie toujours une nouvelle copie de l’état.
- Toutes les mises à jour de l’état sont effectuées en déclenchant une action spécifique.
- Les reducers répondent aux actions et renvoient une nouvelle copie de l’état s’il a été mis à jour.
MobX :

- Peut avoir plusieurs stores observables. La structure de l’état est dénormalisée et souvent profondément imbriquée.
- L’état est mutable. Il peut être modifié directement, mais il est recommandé de le faire à l’aide de fonctions d’action.
- Comme l’indique la documentation : « MobX simplifie à nouveau la gestion de l’état en s’attaquant au problème fondamental : il rend impossible la production d’un état incohérent. »
- Toutes les dérivations sont mises à jour automatiquement et de manière atomique lorsque l’état change.
Store Redux
Comme indiqué précédemment, Redux stocke les données d’état dans un unique store global, qui est la seule source de vérité. Les reducers, qui prennent un objet d’action et renvoient une copie mise à jour de l’état, sont utilisés pour le gérer. L’objet d’action est un simple objet JavaScript contenant le champ type d’action et les champs payload. Les reducers permettent de diviser un objet d’état en unités logiques distinctes, telles que `artistReducer`, `articlesReducer`, `profileReducer`, qui sont ensuite combinées en un seul objet d’état à l’aide de combineReducers. Le store possède les méthodes dispatch et subscribe pour gérer l’état et répondre aux changements. Si, après avoir appelé `dispatch`, l’état est mis à jour, tous les abonnés sont informés. Cependant, cela nécessite beaucoup de code répétitif pour décrire le store, ce qui constitue un inconvénient majeur pour les petits projets. Exemple d’un store sur Redux :
import { createStore } from 'redux';
const initialState = {
artists: [
{
id: 1,
name: 'Cypress Hill'
},
{
id: 2,
name: 'Triple Six Mafia'
}
]
};
// reducer
function artistReducer(state = initialState, action) {
switch (action.type) {
case 'ARTIST_ADD':
return {
...state,
artists: [...state.artists, action.payload]
};
case 'ARTIST_DELETE':
return {
...state,
artists: state.artists.filter(x => x.id !== action.payload)
};
default:
return state;
}
};
// action creators
const artistAddAction = (artist) => {
return {
type: 'ARTIST_ADD',
payload: artist
}
};
const artistDeleteAction = (id) => {
return {
type: 'ARTIST_DELETE',
payload: id
}
};
// selector
const printArtists = (store) => console.log('Artists: ', store.getState().artists.map(x => x.name));
// store
const store = createStore(artistReducer);
printArtists(store);
store.subscribe(() => printArtists(store));
store.dispatch(artistAddAction({ id: 3, name: 'Juicy J' }));
// output
Artists: ["Cypress Hill", "Triple Six Mafia"]
Artists: ["Cypress Hill", "Triple Six Mafia", "Juicy J"]
Store MobX
Une application qui utilise MobX a tendance à avoir plusieurs stores qui divisent l’état en blocs logiques, tels qu’un modèle de domaine ou un état d’interface utilisateur. Cela permet d’organiser la structure de l’état de manière pratique et de réutiliser des stores individuels dans d’autres applications. MobX possède un niveau d’abstraction assez élevé, ce qui réduit considérablement le code répétitif par rapport à Redux. Cela permet de créer rapidement des stores en utilisant les annotations @observable et @computed, ou les fonctions makeObservable et makeAutoObservable. Les changements d’état peuvent être effectués directement, comme `artistStore.artists.push(artist)`, ou, comme il est recommandé, de manière plus explicite en utilisant @action, comme le montre l’exemple ci-dessous. La manière la plus simple de réagir aux changements dans le store est de créer une réaction en passant une fonction de rappel à la fonction autorun. La réaction sera appelée lors de sa première création et chaque fois que les valeurs observable et computed du store changeront. Le principal inconvénient de cette approche est que lorsque les applications commencent à devenir plus complexes, cela entraîne des relations entre les stores peu évidentes et difficiles à déboguer. L’exemple suivant décrit un store MobX similaire au store Redux présenté ci-dessus :
import {observable, action, autorun} from 'mobx';
class artistStore {
@observable artists = [
{
id: 1,
name: 'Cypress Hill'
},
{
id: 2,
name: 'Triple Six Mafia'
}
];
@action addArtist = (artist) => {
this.artists.push(artist);
}
@action deleteArtist = (id) => {
this.artists = this.artists.filter(x => x.id !== id);
}
}
const store = new artistStore();
autorun(() => {
console.log('Artists: ', store.artists.map(x => x.name))
})
store.addArtist({id: 3, name: 'Juicy J'})
// output
Artists: ["Cypress Hill", "Triple Six Mafia"]
Artists: ["Cypress Hill", "Triple Six Mafia", "Juicy J"]
Popularité et compatibilité
À en juger par le puissant soutien de la communauté, Redux est sans aucun doute plus populaire que MobX. Dans cette bibliothèque, tout développeur peut trouver des solutions aux problèmes liés à Redux et utiliser un outil pratique pour déboguer l’état grâce à Redux DevTools. Cela simplifie le processus d’apprentissage de la bibliothèque. Cependant, la nécessité d’écrire une grande quantité de code répétitif et de nombreuses bibliothèques et solutions utilitaires comme redux-saga, redux-thunk, reselect, normalizr, middlewares, etc., est la principale cause de maux de tête sur le chemin de sa maîtrise. Pendant ce temps, MobX offre une abstraction élevée dans les annotations, permettant un passage rapide de l’apprentissage au travail avec la bibliothèque.
MobX et Redux sont des bibliothèques indépendantes qui sont compatibles avec presque tous les frameworks d’interface utilisateur. Pour des solutions populaires comme React, des packages prêts à l’emploi facilitent la connexion et la gestion des états, tels que mobx-react ou react-redux.
Débogage
Le débogage de l’état dans Redux est incroyablement flexible et transparent grâce à son faible niveau d’abstraction, au paradigme Flux et aux pratiques Redux DevTools. Redux DevTools offre la plus large gamme de fonctionnalités pour déboguer l’état, y compris le voyage dans le temps pour les changements d’état, l’import/export de l’état sous forme de fichier .json ordinaire, la génération d’autotest, l’affichage de l’état sous forme d’arbre, de graphiques, pour n’en nommer que quelques-uns. MobX dispose également d’un utilitaire de débogage d’état – MobX DevTools, mais sa fonctionnalité est beaucoup plus limitée par rapport à l’utilitaire pour Redux. Il permet aux utilisateurs de visualiser l’arbre d’état du dépôt et de détecter les changements d’état et le redessin des composants. De plus, MobX est livré avec un certain nombre d’utilitaires tels que trace et spy qui facilitent le débogage de l’état.
Conclusion
Cet article examine deux bibliothèques visant à résoudre un problème mais utilisant des méthodes différentes. Nous avons présenté les avantages et les inconvénients de chaque bibliothèque – le choix vous appartient. Optez pour Redux si votre priorité est de travailler avec un stockage d’état flexible, évolutif, débogable et plus populaire, et qu’une grande quantité de code répétitif ne vous pose pas de problème. Cependant, pour une mise en œuvre rapide d’un stockage dans un petit projet MVP ou PoC, il est préférable d’adopter MobX. Ci-dessous, une courte liste d’avantages et d’inconvénients qui devrait vous aider à choisir l’outil adapté à votre tâche.
- Facile à apprendre
- Peu de code répétitif
- Support complet de TypeScript
- Débogage difficile
- Niveau élevé de liberté en termes de stockage, structuration et traitement des données
- Mise à l’échelle compliquée avec la croissance du projet
- Excellent support communautaire
- Débogage et tests faciles
- Flexibilité et extensibilité grâce aux fonctions de reducer pures et aux middlewares
- Beaucoup de code répétitif
- Absence d’effets secondaires intégrés
- Nécessité d’apprendre de nombreuses bibliothèques supplémentaires