Définissez un state Redux adapté à votre application
Le state de Redux est au centre de l'application. Contrairement à React, qui peut contenir de nombreux states, Redux possède un seul et unique state.
Un seul state pour toute l’application ? Ça risque d'être un peu le bazar, non ?
C’est vrai que dit comme ça, ça ressemble un peu à mon App
immense du chapitre précédent. Mais pas de panique ! Redux est fait pour gérer un tel state, et propose des outils adaptés. Ce state unique apporte d’ailleurs deux avantages majeurs :
Il est simple de décider où l’on met tel ou tel state global.
On peut facilement explorer tous les states globaux de l’application en un coup d'œil, car ils sont tous au même endroit.
Allez, c’est parti ! Pour commencer, essayons de définir ensemble le state de l’application Tennis Score. Cet exercice ne devrait pas vous poser trop de soucis, car c’est un peu la même logique que pour les states React ! Découvrons Tennis Score dans le screencast ci-dessous :
Dans notre state, il nous faut :
le score de chaque joueur ;
s'il y a 40-40, savoir quel joueur a l’avantage ;
savoir qui a gagné ;
savoir si le jeu est en pause.
Alors, vous avez trouvé ? Voici ma solution :
const initialState = {
// Le score de chacun des joueurs
player1: 0,
player2: 0,
// Si il y a 40-40 quel joueur a l'avantage
// On utilise null si pas d'avantage
advantage: null,
// Qui a gagné ?
// Si la partie est en cours on utilise null
winner: null,
// La partie est-elle en cours ?
playing: true
};
Maintenant que nous avons notre state, voyons comment on va pouvoir le modifier.
Listez les changements possibles grâce aux actions
Avec React, pour changer le state, il suffit d'appeler setState
avec la nouvelle valeur. C’est par exemple ce que l’on fait dans dans l’exemple du bouton au premier chapitre, lorsque l’on appelle setCount(count + 1)
.
Dans Redux, c’est différent : on ne modifie pas le state directement. On doit passer par des actions.
J’imagine que ça n’a pas de rapport avec les actions en bourse d’une entreprise ?
Non, en effet ! Une action Redux a une définition bien précise :
c’est un objet JavaScript ;
il décrit la raison d’un changement de notre state ;
cela, grâce à une propriété obligatoire
type
;et il a aussi éventuellement une propriété
payload
qui contient des données additionnelles.
Pourquoi on s'embête à passer par une action plutôt que de changer directement le state comme dans React ?
Pour l’illustrer, parmi les deux listes ci-dessous, laquelle permet le mieux de comprendre ce qu’il se passe ?
- { a: 1, b: 0 } - IncrementA
- { a: 1, b: 1 } - IncrementB
- { a: 2, b: 1 } - IncrementA
- { a: 2, b: 3 } - AddAtoB
- { a: 2, b: 2 } - DecrementB
- { a: 0, b: 0 } - Reset
Eh oui, celle de droite ! Elle décrit les changements, alors que celle de gauche montre uniquement le résultat. C’est pour cette raison que l’on utilise des actions dans Redux : cela permet de comprendre les modifications de state, car chaque étape est accompagnée d’une action qui exprime la raison de ce changement !
Dans le cas de notre application de Tennis Score, nous aurons par exemple besoin de l’action suivante pour mettre le jeu en pause ou le reprendre :
// une action Redux est un objet
const playPauseAction = {
// la propriété type permet d'identifier l'action
type: "playPause"
};
Lorsqu'un joueur gagne un échange, on pourrait utiliser une des deux actions suivantes :
const player1ScoredAction = { type: 'player1Scored' };
const player2ScoredAction = { type: 'player2Scored' };
Ou même mieux ! Utiliser une seule action avec un payload
pour indiquer quel joueur a marqué :
const pointScoredAction = {
type: 'pointScored',
// On utilise payload pour préciser quel joueur a marqué
payload: { player: "player1" }
};
Pour éviter les erreurs, on peut aussi écrire une fonction qui va créer l’action à notre place.
const playPause = () => ({ type: "playPause" });
const pointScored = (player) => ({
type: "pointScored",
payload: { player: player },
});
Utiliser une fonction pour créer une action est très commun dans Redux. Cela a même un nom : “Action Creator”.
Il est maintenant temps d'utiliser ces actions pour changer le state. C’est ce que nous allons faire dans le Reducer !
Faites fonctionner vos actions dans le Reducer
Le Reducer, c’est le cerveau de Redux. C’est là que l'on va mettre la logique de notre application. Un Reducer Redux est une fonction qui reçoit le state et une action en paramètre, et qui retourne un nouveau state.

Voyons ensemble ce que cela donne concrètement pour notre playPause
:
// le reducer est une fonction
function reducer(state, action) {
// si l'action est de type playPause...
if (action.type === "playPause") {
// ... il faut inverser la propriété playing du state
return {
...state,
playing: !state.playing
};
}
// sinon on retourne le state sans le changer
return state;
}
Qu’est-ce que c’est cette syntaxe avec les ...
?
Il s’agit d’une syntaxe de destructuring. Cela permet de créer un nouveau state sans modifier le state précédent :
// on utilise des accolades pour déclarer un nouvel objet
return {
// on déstructure le state précédent, c'est à dire que l'on
// copie toutes ses propriété dans notre nouvel objet
...state,
// on remplace la propriété playing par
// l'inverse de state.playing
playing: !state.playing
};
On est obligé d’utiliser le destructuring ? Pourquoi ne pas écrire state.playing = !state.playing
?
Oui, il faut toujours utiliser le destructuring pour changer le state dans un reducer. Si l’on change directement le state ( state.playing = !state.playing
), Redux ne peut pas détecter le changement, ce qui posera des problèmes pour la suite.
En revanche, si on ne change pas le state, on peut le retourner directement. C’est ce que l’on fait ici à l’avant-dernière ligne avec return state
. De cette manière, même en cas d’action invalide, le reducer retourne quand même un state.
Revenons maintenant sur ce que l’on vient de voir dans le screencast ci-dessous :
Vous pouvez explorer le codepen de base utilisé dans le screencast juste ici.
Mais au fait, on parle de Redux depuis le début de ce chapitre, mais on ne l’a toujours pas installé. On va remédier à ça dans la section suivante avec la création du Store !
Assemblez state, action et reducer grâce au Store
Nous avons maintenant tous les ingrédients prêts : le state, les actions et le reducer. Il est temps de les faire fonctionner ensemble grâce au Store !
Le Store de Redux, c’est un peu comme les œufs dans une tarte : c’est ce qui lie tous les ingrédients ensemble.
Commençons par ajouter Redux à notre application. Pour cela, nous allons ajouter la ligne de code suivante en haut de notre fichier JavaScript :
import { createStore } from "https://cdn.skypack.dev/redux@4.0.5";
Ici on importe la fonction createStore
. Cette fonction attend deux paramètres : le reducer et le state initial que nous avons déjà créés dans les sections précédentes !
// on crée le store avec le state et le reducer
const store = createStore(reducer, initialState);
Une fois le store créé, on peut lire le state à tout moment grâce à la fonction store.getState
:
const state = store.getState();
// { playing: true, ... }
Est-ce qu’il y a aussi une fonction store.setState
pour changer le state ?
Oui, mais cette fonction ne s'appelle pas setState
, mais dispatch
. C’est grâce à elle que l’on va pouvoir utiliser nos actions.
// on passe un objet action
store.dispatch({ type: "playPause" });
// on passe une action depuis une variable
store.dispatch(playPauseAction);
// on passe une action en utilisant un action creator
// attention à bien appeler la fonction pointScored !
store.dispatch(pointScored("player2"));
Si l’on appelle une nouvelle fois getState
, on constate que le state a bien changé !
const state = store.getState();
// { playing: false, ... }
Bravo ! Vous venez de mettre en place la logique Redux !

On peut maintenant utiliser getState
pour mettre à jour l’affichage et dispatch
lorsqu’un bouton est cliqué :
pauseButton.addEventListener("click", function () {
store.dispatch(playPause());
});
const state = store.getState();
updateScoreText(state.playing);
Attention cependant, car contrairement à React, ici l’affichage ne se mettra pas à jour automatiquement. Pour résoudre cela, on peut utiliser la fonction subscribe
du store pour exécuter du code dès que le state change.
La fonction subscribe
attend un seul argument : une fonction à exécuter quand le state change. Dans notre cas, nous allons récupérer le state avec getState
et mettre à jour l’affichage avec updateScoreText
:
store.subscribe(
// cette fonction sera exécutée à chaque fois que le state change
() => {
const state = store.getState();
updateScoreText(state.playing);
}
);
Revenons sur toutes les étapes qu’il nous faut pour créer et utiliser le store ci-dessous :
Vous avez désormais toutes les cartes en main pour utiliser Redux ! Dans la prochaine section, vous allez pouvoir mettre en pratique ce que vous avez appris !
Exercez-vous
Il est temps pour vous de faire fonctionner l’application Tennis Score. Vous trouverez le codepen de base juste ici. Il contient déjà :
la structure HTML de l’application ;
le style CSS ;
une fonction
updateScoreText
qui permet de mettre à jour l’affichage ;un moyen d'exécuter du code lorsque les boutons sont cliqués (
addEventListener
).
Votre mission, si vous l’acceptez, sera de :
créer le state initial de l’application ;
imaginer les actions et créer les action creators ;
créer un reducer pour implémenter la logique de l’application ;
importer Redux et créer le store ;
appeler la fonction
dispatch
au clic sur les boutons ;utiliser la fonction
subscribe
pour automatiquement mettre à jour l’affichage quand le state change.
Si vous avez du mal à vous lancer, vous pouvez regarder de nouveau les screencasts de ce chapitre, ils vous montrent les différentes étapes à effectuer.
Solution
Vous trouverez ci-dessous un screencast qui détaille la solution de cet exercice :
Vous trouverez également le code de ce corrigé à cette adresse CodePen.
En résumé
Redux est organisé en différents concepts :
Le state, qui joue le même rôle que le state React, sauf que dans Redux on utilise un seul state global pour toute notre application.
Les actions, qui permettent de décrire les différents changements de state.
Le reducer, qui utilise le state et les actions pour implémenter la logique de notre application.
Et enfin, le Store, qui vient lier tous les éléments ensemble.
Vous commencez à voir les avantages de Redux ? Et pourtant vous n’avez encore rien vu ! En effet, Redux prend tout son sens lorsqu’il est combiné à React ; c’est ce que nous allons voir ensemble dans la partie 2 ! Mais avant de continuer, n’oubliez pas de valider ce que vous avez appris avec le quiz – c’est parti !