Logique métier découplée de l'UI : la règle qui sauve les pivots produit
Une logique métier dans le composant React = impossible à tester, à réutiliser, à migrer. Découpler = pouvoir changer l'UI sans toucher au métier (et vice-versa).
Les 3 couches
UI (React composants) ← présentation pure
└── Hooks (useFoo) ← orchestration React
└── Services (TS pur) ← logique métier testable
└── API/DB ← persistanceExemple : calcul de pricing
// ❌ logique dans le composant
function PricingCard() {
const price = base * (1 + tva) * (1 - discount);
return <div>{price.toFixed(2)} €</div>;
}
// ✅ service TS pur, testable, réutilisable
// src/features/pricing/pricing.service.ts
export function computePrice(input: PricingInput): number { ... }
// hook React
function usePricing(input) {
return useMemo(() => computePrice(input), [input]);
}
// composant
function PricingCard({ input }) {
const price = usePricing(input);
return <div>{formatEUR(price)}</div>;
}Bénéfices
- Tests unitaires sur
computePrice(0 React, vitest rapide) - Réutilisable côté edge function (même formule serveur/client)
- Pivot UI sans risque (le métier reste figé)
- Documentation in-file naturelle (1 fonction = 1 contrat)
Anti-pattern : services qui dépendent de React
computePrice(useUser()) = service couplé. Refuse useState/useEffect dans *.service.ts. La couche TS pur ne doit rien savoir de React.
Validation des entrées avec Zod
Chaque service expose un schéma Zod en entrée. Sortie typée. Les erreurs de validation deviennent des ApiError(422, ...) côté edge. UI affiche le détail par champ.
Partager