Un bloc « comparateur de forfaits », décliné en plusieurs instances sur la même page, qui doivent toutes partager un même panier de comparaison sans qu’aucune ne connaisse directement les autres : ce genre de besoin dépasse ce que useState local ou même les stores natifs de WordPress peuvent raisonnablement couvrir. C’est exactement le cas d’usage pour lequel createReduxStore, du paquet @wordpress/data, a été pensé.
Quand un store personnalisé se justifie
Avant de se lancer dans la création d’un store, il vaut la peine de vérifier que le besoin dépasse réellement ce qu’un état local React (useState) ou les stores natifs (core, core/editor, core/block-editor) peuvent couvrir. Un store personnalisé devient pertinent quand plusieurs instances d’un même bloc, voire plusieurs blocs différents, doivent partager un état cohérent qui ne correspond à aucune entité déjà exposée par WordPress.
Étape 1 : définir l’état initial et le reducer
const DEFAULT_STATE = {
forfaitsCompares: [],
};
function reducer( state = DEFAULT_STATE, action ) {
switch ( action.type ) {
case 'AJOUTER_FORFAIT':
return {
...state,
forfaitsCompares: [ ...state.forfaitsCompares, action.forfaitId ],
};
case 'RETIRER_FORFAIT':
return {
...state,
forfaitsCompares: state.forfaitsCompares.filter(
( id ) => id !== action.forfaitId
),
};
default:
return state;
}
}
Étape 2 : actions et sélecteurs

const actions = {
ajouterForfait( forfaitId ) {
return { type: 'AJOUTER_FORFAIT', forfaitId };
},
retirerForfait( forfaitId ) {
return { type: 'RETIRER_FORFAIT', forfaitId };
},
};
const selectors = {
getForfaitsCompares( state ) {
return state.forfaitsCompares;
},
};
Les actions restent de simples fonctions qui renvoient un objet décrivant l’événement survenu, exactement comme dans Redux classique. Les sélecteurs, eux, ne font que lire l’état, sans jamais le modifier directement.
Étape 3 : createReduxStore et register
import { createReduxStore, register } from '@wordpress/data';
const STORE_NAME = 'mon-projet/comparateur';
const store = createReduxStore( STORE_NAME, {
reducer,
actions,
selectors,
} );
register( store );
Une fois register appelé, ce store devient disponible exactement comme n’importe quel store natif, via useSelect et useDispatch, depuis n’importe quel bloc du site :
import { useSelect, useDispatch } from '@wordpress/data';
const forfaits = useSelect(
( select ) => select( STORE_NAME ).getForfaitsCompares(),
[]
);
const { ajouterForfait } = useDispatch( STORE_NAME );
Étape 4 : des resolvers pour le chargement asynchrone
Si l’état initial doit être peuplé depuis une requête REST plutôt que de démarrer vide, un resolver associé à un sélecteur déclenche automatiquement le chargement dès que ce sélecteur est appelé pour la première fois, sans code manuel dans le composant :
import apiFetch from '@wordpress/api-fetch';
const resolvers = {
*getForfaitsCompares() {
const forfaits = yield apiFetch( { path: '/mon-projet/v1/comparateur' } );
return actions.hydraterForfaits( forfaits );
},
};
Cette syntaxe en générateur permet d’écrire du code asynchrone qui ressemble à du code synchrone, sans manipuler directement de promesses dans le composant React qui consomme le store.
Les limites à connaître
- Un store personnalisé ajoute une complexité réelle : il ne se justifie pas pour un état qui reste local à une seule instance de bloc.
- L’état d’un store
@wordpress/datan’est pas persisté automatiquement entre deux rechargements de page, contrairement à un stockage local du navigateur. - Un store mal nommé (sans espace de noms propre à l’extension) risque une collision avec un autre store enregistré sur le même site.
Sur un projet avec un seul bloc concerné, un état local suffit presque toujours ; le passage à un store dédié se justifie surtout à partir du moment où deux blocs distincts doivent réellement se synchroniser.
En résumé
createReduxStore ouvre la voie à des blocs bien plus riches en données, capables de coordonner leur état à travers toute une page, au prix d’un peu plus de code de mise en place. Cette option reste réservée aux cas où les stores natifs de WordPress, déjà couverts par ailleurs, ne suffisent réellement plus.