mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-04-06 21:41:42 +02:00
355 lines
11 KiB
Markdown
355 lines
11 KiB
Markdown
# Patterns front-end validés
|
||
|
||
Ce fichier contient **uniquement** des patterns front-end :
|
||
|
||
- testés,
|
||
- validés,
|
||
- utilisés dans des projets réels (ou des apps complètes, pas des snippets isolés).
|
||
|
||
Il sert de **mémoire durable** pour éviter :
|
||
|
||
- de refaire les mêmes erreurs,
|
||
- de redélibérer éternellement sur des sujets déjà tranchés,
|
||
- de propager des “bonnes pratiques” théoriques non éprouvées.
|
||
|
||
Dernière mise à jour : 12-03-2026
|
||
|
||
---
|
||
|
||
## Index
|
||
|
||
- [Gestion explicite des états UI (loading / empty / error)](#pattern-etats-ui-loading-empty-error)
|
||
- [Séparation claire server state / client state](#pattern-separation-server-state-client-state)
|
||
- [Formulaire robuste avec validation et erreurs explicites](#pattern-formulaire-robuste)
|
||
- [Navigation réactive post-action async (React / Expo Router)](#pattern-navigation-reactive-post-action-async)
|
||
- [Refresh idempotent sur store de liste paginée](#pattern-refresh-idempotent-liste-paginee)
|
||
|
||
---
|
||
|
||
## Règle d’or
|
||
|
||
Si ce n’est pas **confirmé comme fonctionnel et utile**,
|
||
**ça n’a rien à faire ici**.
|
||
|
||
- Pas de conseils vagues
|
||
- Pas de patterns “à la mode”
|
||
- Pas de dépendance implicite à un framework ou une version non précisée
|
||
|
||
---
|
||
|
||
## Périmètre couvert
|
||
|
||
- SPA et webapps
|
||
- UX technique (forms, erreurs, loading, feedback)
|
||
- State management (client / server)
|
||
- Architecture front-end
|
||
- Performance et accessibilité
|
||
- Sécurité front (au niveau applicatif)
|
||
- DX et maintenabilité
|
||
|
||
Ce fichier traite le **front-end comme un logiciel en production**,
|
||
au même niveau d’exigence que le backend.
|
||
|
||
---
|
||
|
||
## Format standard d’un pattern (obligatoire)
|
||
|
||
## Pattern : <Nom clair et précis>
|
||
|
||
- Objectif : ce que le pattern résout
|
||
- Contexte : type d’application / contraintes
|
||
- Quand l’utiliser : cas pertinents
|
||
- Quand l’éviter : contre-exemples
|
||
- Avantages : bénéfices concrets
|
||
- Limites / vigilance : pièges, dette potentielle
|
||
- Validé le : DD-MM-YYYY
|
||
- Contexte technique : framework + version + tooling principal
|
||
|
||
### Implémentation (exemple minimal)
|
||
|
||
```txt
|
||
(contenu volontairement minimal, lisible, non-magique)
|
||
```
|
||
|
||
---
|
||
|
||
<a id="pattern-etats-ui-loading-empty-error"></a>
|
||
## Pattern : Gestion explicite des états UI (loading / empty / error)
|
||
|
||
### Synthèse
|
||
|
||
- **Objectif** : éviter les interfaces ambiguës ou incohérentes en rendant explicites tous les états possibles d’une vue.
|
||
- **Contexte** : SPA ou webapp consommant des données asynchrones (API, backend, cache).
|
||
- **Quand l’utiliser** : dès qu’une vue dépend de données externes ou d’un traitement async.
|
||
- **Quand l’éviter** : vues purement statiques ou synchrones sans dépendance externe.
|
||
|
||
### Analyse
|
||
|
||
- **Avantages** :
|
||
- UX plus prévisible et compréhensible
|
||
- Debug facilité (état visible = problème identifiable)
|
||
- Base saine pour tests et accessibilité
|
||
- **Limites / vigilance** :
|
||
- Peut sembler verbeux sur des écrans simples
|
||
- Nécessite une discipline pour ne pas “court-circuiter” les états
|
||
|
||
### Validation
|
||
|
||
- Validé le : 25-01-2026
|
||
- Contexte technique : SPA (React / Vue / Svelte agnostique), API HTTP
|
||
|
||
### Implémentation (exemple minimal)
|
||
|
||
```txt
|
||
if (loading) {
|
||
afficher un skeleton ou spinner
|
||
} else if (error) {
|
||
afficher un message clair + action possible
|
||
} else if (data est vide) {
|
||
afficher un état empty explicite
|
||
} else {
|
||
afficher la vue nominale
|
||
}
|
||
```
|
||
|
||
### Checklist
|
||
|
||
- [ ] Aucun écran blanc ou silencieux
|
||
- [ ] Message d’erreur compréhensible pour l’utilisateur
|
||
- [ ] États testables individuellement
|
||
- [ ] Accessibilité respectée (focus, lecture écran)
|
||
- [ ] Pas de logique métier cachée dans le rendu
|
||
|
||
---
|
||
|
||
<a id="pattern-separation-server-state-client-state"></a>
|
||
## Pattern : Séparation claire server state / client state
|
||
|
||
### Synthèse
|
||
|
||
- **Objectif** : éviter le mélange des responsabilités entre données serveur et état local UI.
|
||
- **Contexte** : SPA ou webapp consommant une API avec interactions utilisateur.
|
||
- **Quand l’utiliser** : dès que l’application affiche des données distantes modifiables ou synchronisées.
|
||
- **Quand l’éviter** : applications très simples ou purement statiques.
|
||
|
||
### Analyse
|
||
|
||
- **Avantages** :
|
||
- Logique plus lisible et testable
|
||
- Réduction des bugs liés aux états incohérents
|
||
- Évolutivité facilitée quand l’app grossit
|
||
- **Limites / vigilance** :
|
||
- Demande de la rigueur dans le découpage
|
||
- Peut sembler abstrait au début pour des petits projets
|
||
|
||
### Validation
|
||
|
||
- Validé le : 25-01-2026
|
||
- Contexte technique : SPA agnostique (React / Vue / Svelte), API HTTP
|
||
|
||
### Implémentation (exemple minimal)
|
||
|
||
```txt
|
||
serverState = données venant du backend (fetch, cache, sync)
|
||
clientState = état local UI (filtres, onglets, modales, formulaires)
|
||
|
||
Ne jamais :
|
||
- stocker du state UI dans le cache serveur
|
||
- dériver la logique UI directement des réponses API sans adaptation
|
||
```
|
||
|
||
### Checklist
|
||
|
||
- [ ] Les données serveur peuvent être invalidées / rechargées
|
||
- [ ] L’état UI est local et réinitialisable
|
||
- [ ] Les responsabilités sont lisibles dans le code
|
||
- [ ] Les tests peuvent cibler chaque type d’état
|
||
- [ ] Pas de dépendance implicite entre UI et API
|
||
|
||
---
|
||
|
||
<a id="pattern-formulaire-robuste"></a>
|
||
## Pattern : Formulaire robuste avec validation et erreurs explicites
|
||
|
||
### Synthèse
|
||
|
||
- **Objectif** : garantir des formulaires fiables, compréhensibles et maintenables.
|
||
- **Contexte** : toute interface avec saisie utilisateur et règles métier.
|
||
- **Quand l’utiliser** : dès qu’un formulaire dépasse un simple champ isolé.
|
||
- **Quand l’éviter** : formulaires ultra-simples sans validation réelle.
|
||
|
||
### Analyse
|
||
|
||
- **Avantages** :
|
||
- UX claire (l’utilisateur sait quoi corriger)
|
||
- Moins d’erreurs silencieuses
|
||
- Base saine pour tests et accessibilité
|
||
- **Limites / vigilance** :
|
||
- Peut sembler verbeux sans discipline
|
||
- Risque de duplication si mal factorisé
|
||
|
||
### Validation
|
||
|
||
- Validé le : 25-01-2026
|
||
- Contexte technique : Front-end agnostique, API HTTP
|
||
|
||
### Implémentation (exemple minimal)
|
||
|
||
```txt
|
||
- Validation côté client (format, champs requis)
|
||
- Validation côté serveur (règles métier)
|
||
- Mapping explicite des erreurs serveur → champs UI
|
||
- Aucun submit silencieux
|
||
```
|
||
|
||
### Checklist
|
||
|
||
- [ ] Messages d’erreur compréhensibles et localisés
|
||
- [ ] Validation client + serveur cohérente
|
||
- [ ] Focus automatique sur le champ en erreur
|
||
- [ ] États loading / disabled gérés
|
||
- [ ] Tests sur cas valides et invalides
|
||
|
||
---
|
||
|
||
<a id="pattern-navigation-reactive-post-action-async"></a>
|
||
## Pattern : Navigation réactive post-action async (React / Expo Router)
|
||
|
||
### Synthèse
|
||
|
||
- **Objectif** : déclencher la navigation après une action asynchrone (login, register, submit) de façon idiomatique et sans bypasser la réactivité React.
|
||
- **Contexte** : SPA ou app mobile React avec state management (Zustand, Redux, Context) et router déclaratif (React Router, Expo Router, Next.js App Router).
|
||
- **Quand l'utiliser** : dès qu'une navigation dépend du résultat d'une action async.
|
||
- **Quand l'éviter** : navigations synchrones sans état async impliqué.
|
||
|
||
### Analyse
|
||
|
||
- **Avantages** :
|
||
- Respecte le cycle de vie React (pas de lecture de state hors cycle)
|
||
- Re-render automatique si l'état change entre-temps
|
||
- Testable : on peut assert sur l'état, pas sur des effets de bord
|
||
- **Limites / vigilance** :
|
||
- Ne pas oublier les dépendances du `useEffect` (ESLint react-hooks/exhaustive-deps)
|
||
- Gérer le cas "composant démonté" si la navigation peut être annulée
|
||
|
||
### Validation
|
||
|
||
- Validé le : 07-03-2026
|
||
- Contexte technique : React 18+ / Zustand / Expo Router — pattern applicable sur React Router, Next.js App Router
|
||
|
||
### Implémentation (exemple minimal)
|
||
|
||
```typescript
|
||
// ❌ Anti-pattern : lecture de state hors cycle React
|
||
const handleSubmit = async () => {
|
||
await login(email, password);
|
||
const { accessToken } = useAuthStore.getState(); // bypasse la réactivité
|
||
if (accessToken) router.replace('/(tabs)');
|
||
};
|
||
|
||
// ✅ Pattern correct : useEffect réactif sur le state
|
||
const { accessToken, isLoading, error } = useAuthStore();
|
||
|
||
useEffect(() => {
|
||
if (accessToken && !isLoading && !error) {
|
||
router.replace('/(tabs)');
|
||
}
|
||
}, [accessToken, isLoading, error]);
|
||
|
||
const handleSubmit = async () => {
|
||
await login(email, password);
|
||
// la navigation se déclenche via useEffect quand le store se met à jour
|
||
};
|
||
```
|
||
|
||
### Pour les callbacks OAuth (ref nécessaire)
|
||
|
||
```typescript
|
||
// Quand un callback externe déclenche la navigation
|
||
const pendingOAuth = useRef(false);
|
||
|
||
useEffect(() => {
|
||
if (pendingOAuth.current && accessToken) {
|
||
pendingOAuth.current = false;
|
||
router.replace('/(tabs)');
|
||
}
|
||
}, [accessToken]);
|
||
|
||
const handleOAuth = async () => {
|
||
pendingOAuth.current = true;
|
||
await exchangeWithIdp(token);
|
||
};
|
||
```
|
||
|
||
### Checklist
|
||
|
||
- [ ] Aucun `store.getState()` utilisé pour lire l'état post-action dans un handler
|
||
- [ ] `useEffect` avec dépendances explicites (state pertinent + isLoading + error)
|
||
- [ ] Cas d'erreur géré (ne pas naviguer si error est défini)
|
||
- [ ] `useRef` si le trigger vient d'un callback externe (OAuth, deep link)
|
||
- [ ] Convention documentée dans la story foundations / project-context avant les premiers écrans
|
||
|
||
---
|
||
|
||
<a id="pattern-refresh-idempotent-liste-paginee"></a>
|
||
## Pattern : Refresh idempotent sur store de liste paginée
|
||
|
||
### Synthèse
|
||
|
||
- **Objectif** : garantir qu’un pull-to-refresh recharge une liste paginée sans doublons, sans courses réseau et sans état intermédiaire incohérent.
|
||
- **Contexte** : app mobile ou SPA avec store de domaine (ex. Zustand) et pagination incrémentale.
|
||
- **Quand l’utiliser** : dès qu’une même liste supporte à la fois `loadMore` et `refresh`.
|
||
- **Quand l’éviter** : listes purement statiques ou données entièrement remplacées sans pagination.
|
||
|
||
### Analyse
|
||
|
||
- **Avantages** :
|
||
- évite les doublons lors des refresh concurrents
|
||
- garde une transition atomique entre ancien et nouvel état
|
||
- rend le comportement async testable côté store
|
||
- **Limites / vigilance** :
|
||
- impose une discipline claire entre `refresh` et `loadMore`
|
||
- demande une clé d’identité stable pour dédupliquer les items
|
||
|
||
### Validation
|
||
|
||
- Validé le : 10-03-2026
|
||
- Contexte technique : React Native / Expo / Zustand / listes paginées
|
||
|
||
### Implémentation (exemple minimal)
|
||
|
||
```txt
|
||
- conserver une promesse de refresh partagée tant qu’un refresh est en vol
|
||
- refuser ou réutiliser tout refresh concurrent au lieu d’en lancer un second
|
||
- remplacer atomiquement la liste à la fin du refresh
|
||
- dédupliquer les items par identifiant au merge des pages suivantes
|
||
- empêcher `loadMore` de fusionner sur un snapshot devenu obsolète
|
||
```
|
||
|
||
### Checklist
|
||
|
||
- [ ] Une seule promesse de refresh en vol à la fois
|
||
- [ ] `refresh` et `loadMore` ont des garde-fous explicites
|
||
- [ ] La liste est remplacée atomiquement après refresh
|
||
- [ ] Les pages suivantes sont dédupliquées par identifiant stable
|
||
- [ ] Tests sur refresh concurrent + refresh suivi de pagination
|
||
|
||
---
|
||
|
||
### Principes transverses
|
||
|
||
- Un pattern = une responsabilité claire
|
||
- On privilégie la simplicité locale avant la généricité globale
|
||
- Le code doit rester compréhensible 6 mois plus tard
|
||
- Si un pattern devient central → il mérite une décision d’architecture dédiée
|
||
|
||
⸻
|
||
|
||
## Notes importantes
|
||
|
||
- 3 bons patterns > 30 moyens
|
||
- Si un pattern évolue :
|
||
- on met à jour la date
|
||
- on précise le nouveau contexte
|
||
- En cas de doute → le pattern n’entre pas encore ici
|