# createReduxStore : un store @wordpress/data pour un bloc complexe

> Quand les stores natifs ne suffisent plus, créer et enregistrer son propre store avec createReduxStore, actions, sélecteurs et resolvers, pour un bloc riche en données.

- Auteur : Clément Hadrot
- Publié le : 2022-06-01
- Mis à jour le : 2022-06-01
- Catégorie : Blocs Gutenberg
- URL : https://wpmoderne.dev.wordpress-developpement.fr/blocs/createreduxstore-store-data-bloc-complexe/

## L’essentiel

- Un store personnalisé se justifie quand plusieurs blocs partagent un même état
- Les resolvers gèrent le chargement asynchrone sans code manuel dans le composant
- register() rend le store disponible à useSelect comme n'importe quel store natif

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

> L'essentiel à retenir : Un store personnalisé se justifie quand plusieurs blocs partagent un même état ; Les resolvers gèrent le chargement asynchrone sans code manuel dans le composant ; register() rend le store disponible à useSelect comme n'importe quel store natif

```
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/data` n'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.
