# Un calculateur de devis interactif avec Interactivity API

> Un artisan menuisier voulait un simulateur de prix en front sans alourdir son site d'un framework JavaScript. L'Interactivity API a rendu ce compromis possible.

- Auteur : Clément Hadrot
- Publié le : 2023-03-21
- Mis à jour le : 2023-03-21
- Catégorie : Blocs Gutenberg
- URL : https://wpmoderne.dev.wordpress-developpement.fr/blocs/calculateur-devis-interactif-interactivity-api/

## L’essentiel

- Le state central porte les dimensions saisies par le visiteur
- Une fonction dérivée recalcule le prix sans stockage redondant
- data-wp-bind synchronise l'affichage sans manipulation du DOM manuelle

Un artisan menuisier, spécialisé dans la fabrication de bibliothèques sur mesure, voulait proposer sur son site un simulateur permettant à un visiteur d'indiquer largeur et hauteur souhaitées pour obtenir instantanément une estimation de prix, sans devoir attendre un rappel téléphonique. La contrainte était claire : pas question d'alourdir un site déjà sensible sur les performances avec un framework JavaScript complet uniquement pour ce petit composant. L'Interactivity API, disponible depuis WordPress 6.5, a permis de livrer ce calculateur avec une quantité de JavaScript minimale, entièrement intégrée au système de blocs natif.

Ce cas illustre bien la logique de conception de cette API : un état central partagé, des valeurs dérivées calculées à la volée plutôt que stockées, et des directives déclaratives dans le HTML qui remplacent la manipulation manuelle du DOM habituellement nécessaire en JavaScript classique.

## Définir le store avec un état et des dérivés

```
import { store, getContext } from '@wordpress/interactivity';

store( 'menuiserie/devis', {
    state: {
        largeur: 100,
        hauteur: 200,
        prixAuMetreCarre: 180,
    },
    getters: {
        prixEstime() {
            const { largeur, hauteur, prixAuMetreCarre } = store( 'menuiserie/devis' ).state;
            const surface = ( largeur / 100 ) * ( hauteur / 100 );
            return Math.round( surface * prixAuMetreCarre );
        },
    },
    actions: {
        modifierLargeur( event ) {
            store( 'menuiserie/devis' ).state.largeur = Number( event.target.value );
        },
        modifierHauteur( event ) {
            store( 'menuiserie/devis' ).state.hauteur = Number( event.target.value );
        },
    },
} );
```

Le prix estimé n'est jamais stocké directement : il s'agit d'un getter, recalculé automatiquement chaque fois que la largeur ou la hauteur change, ce qui élimine tout risque d'incohérence entre les dimensions affichées et le prix correspondant.

## Le balisage côté save avec les directives

> L'essentiel à retenir : Le state central porte les dimensions saisies par le visiteur ; Une fonction dérivée recalcule le prix sans stockage redondant ; data-wp-bind synchronise l'affichage sans manipulation du DOM manuelle

```
<div data-wp-interactive="menuiserie/devis">
    <label>Largeur (cm)
        <input type="number" data-wp-bind--value="state.largeur" data-wp-on--input="actions.modifierLargeur" />
    </label>
    <label>Hauteur (cm)
        <input type="number" data-wp-bind--value="state.hauteur" data-wp-on--input="actions.modifierHauteur" />
    </label>
    <p>Estimation : <span data-wp-text="state.prixEstime"></span> euros</p>
</div>
```

La directive `data-wp-bind--value` synchronise la valeur du champ avec l'état, `data-wp-on--input` déclenche l'action à chaque saisie, et `data-wp-text` affiche la valeur dérivée directement dans le texte de l'élément, sans qu'aucun code JavaScript ne manipule explicitement le DOM à la main.

## Pourquoi cette approche reste légère

Contrairement à une solution basée sur un framework front complet, l'Interactivity API ne charge que le runtime strictement nécessaire à l'exécution des directives présentes sur la page, un script partagé par l'ensemble des blocs interactifs du site plutôt qu'un bundle dédié à chaque composant. Sur le projet du menuisier, l'ajout de ce calculateur n'a fait varier le poids total des scripts chargés que de quelques kilo-octets, une différence négligeable comparée à l'intégration d'une bibliothèque de gestion d'état complète.

## Gérer les cas limites du formulaire

Un calculateur de prix mal protégé accepte n'importe quelle saisie, y compris des valeurs négatives ou nulles qui produiraient une estimation absurde. L'action modifiant l'état a été complétée pour borner les valeurs acceptées avant de les affecter au state.

```
actions: {
    modifierLargeur( event ) {
        const valeur = Number( event.target.value );
        store( 'menuiserie/devis' ).state.largeur = Math.max( 20, Math.min( valeur, 400 ) );
    },
},
```

- Borner systématiquement les valeurs numériques saisies par un visiteur avant tout calcul dérivé.
- Prévoir un message explicite quand la surface calculée dépasse un seuil nécessitant un devis manuel plutôt qu'une estimation automatique.
- Tester le comportement avec le clavier seul, sans souris, avant de considérer le composant terminé.

> Un simulateur de prix qui n'affiche jamais d'avertissement face à une saisie absurde n'est pas un outil rassurant pour un client final, c'est une source de devis erronés qu'il faudra corriger à la main plus tard.

## Ce qu'il faut retenir

Ce projet illustre bien le compromis que l'Interactivity API rend possible pour des besoins réels d'artisans et de petites structures : une interactivité front convaincante, sans le coût de performance d'un framework JavaScript complet, tout en restant pleinement intégrée à l'écosystème de blocs natifs de WordPress plutôt qu'ajoutée en parallèle comme un script indépendant du reste du site.
