
Actions et payloads
Comprenez le rôle des objets 'action' (avec type et payload) dans le pattern Reducer utilisé par useReducer et Redux pour décrire les mises à jour d'état.
Les Actions : Décrire l'intention de changement
Dans le pattern Reducer (utilisé par `useReducer` et Redux), une action est un simple objet JavaScript qui sert de "message" pour indiquer qu'un certain type d'événement s'est produit et qu'une modification de l'état est souhaitée. L'action ne contient pas la logique de mise à jour elle-même ; elle ne fait que décrire l'intention de changement.
C'est la fonction dispatch qui prend cet objet action et le transmet au reducer. Le reducer examine ensuite l'action pour déterminer comment il doit calculer le nouvel état.
La structure d'un objet action est une convention, mais la plus largement adoptée (rendue populaire par Redux) est d'inclure au minimum une propriété type.
La propriété `type` : Identifier l'action
La propriété type est obligatoire et sert d'identifiant unique pour le type d'action effectuée. C'est généralement une chaîne de caractères, souvent écrite en majuscules avec des underscores pour séparer les mots (par exemple, 'INCREMENT', 'ADD_TODO', 'FETCH_DATA_SUCCESS').
Le reducer utilise cette propriété type (typiquement dans une instruction switch) pour déterminer quelle logique de mise à jour exécuter.
// Exemples d'objets action simples (sans payload)
dispatch({ type: 'INCREMENT' });
dispatch({ type: 'RESET_FORM' });
dispatch({ type: 'LOGOUT_USER' });
Le choix des noms de types est important pour la lisibilité. Ils doivent être descriptifs de l'événement qui s'est produit.
La propriété `payload` : Fournir les données nécessaires
Souvent, pour calculer le nouvel état, le reducer a besoin d'informations supplémentaires au-delà du simple type d'action. Par exemple, si l'action est 'ADD_TODO', le reducer a besoin de savoir quel est le texte de la nouvelle tâche à ajouter. Si l'action est 'SET_USERNAME', il a besoin du nouveau nom d'utilisateur.
C'est là qu'intervient la propriété payload (charge utile). C'est une convention (le nom pourrait être différent, mais `payload` est très courant) pour inclure toutes les données additionnelles nécessaires à l'action dans l'objet action.
La valeur de payload peut être de n'importe quel type : une chaîne, un nombre, un objet, un tableau, etc.
// Exemples d'actions avec payload
// Ajouter une tâche
dispatch({
type: 'ADD_TODO',
payload: 'Apprendre useReducer' // Le payload est le texte de la tâche
});
// Définir une valeur spécifique pour un compteur
dispatch({
type: 'SET_COUNTER_VALUE',
payload: 100 // Le payload est la nouvelle valeur
});
// Mettre à jour un champ de formulaire
dispatch({
type: 'UPDATE_FIELD',
payload: { fieldName: 'email', value: 'test@example.com' } // Le payload est un objet
});
// Stocker des données reçues d'une API
dispatch({
type: 'FETCH_DATA_SUCCESS',
payload: [{ id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }] // Le payload est un tableau
});
// Signaler une erreur
dispatch({
type: 'FETCH_DATA_ERROR',
payload: 'Impossible de charger les données' // Le payload est le message d'erreur
});
Dans le reducer, vous accéderez ensuite à ces données via action.payload à l'intérieur du case correspondant.
function myReducer(state, action) {
switch (action.type) {
case 'SET_COUNTER_VALUE':
// Accède à action.payload pour obtenir la nouvelle valeur
return { ...state, count: action.payload };
case 'UPDATE_FIELD':
// Accède aux propriétés de action.payload
return {
...state,
form: {
...state.form,
[action.payload.fieldName]: action.payload.value
}
};
// ... autres cases
default:
return state;
}
}
Conventions et bonnes pratiques
- Types explicites : Utilisez des chaînes descriptives pour les types d'action. Dans des projets plus grands, il est courant de définir ces types comme des constantes pour éviter les fautes de frappe :
const ADD_TODO = 'ADD_TODO'; dispatch({ type: ADD_TODO, payload: ... }); - Structure minimale : N'incluez dans le payload que les informations strictement nécessaires au reducer pour calculer le nouvel état. Evitez d'y mettre des fonctions ou des éléments non sérialisables si vous prévoyez d'utiliser des outils comme Redux DevTools.
- Clarté du `payload` : Si le payload contient plusieurs informations, un objet avec des clés descriptives (comme dans l'exemple
UPDATE_FIELD) est souvent plus clair qu'un simple tableau ou une valeur unique. - Action Creators (optionnel, surtout avec Redux) : Dans des applications plus complexes (surtout avec Redux), on utilise souvent des fonctions appelées "Action Creators" qui créent et retournent l'objet action. Cela aide à standardiser la création des actions et peut encapsuler une logique simple.
// Action creator function addTodo(text) { return { type: 'ADD_TODO', payload: text }; } // Utilisation dispatch(addTodo('Acheter du lait'));
Conclusion : Des messages clairs pour des mises à jour prévisibles
Les actions, avec leurs propriétés type et payload, sont au coeur du fonctionnement de `useReducer` et de Redux. Elles servent de mécanisme de communication standardisé entre l'interface utilisateur (qui déclenche le dispatch) et la logique d'état (le reducer).
En décrivant clairement l'intention de changement (type) et en fournissant les données nécessaires (payload), les actions permettent au reducer de fonctionner de manière prévisible et découplée. Adopter des conventions claires pour vos actions rend votre code de gestion d'état plus facile à comprendre, à déboguer et à maintenir.