mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-04-06 13:31:43 +02:00
169 lines
6.1 KiB
Markdown
169 lines
6.1 KiB
Markdown
# Frontend — Patterns : Navigation
|
|
|
|
> Extrait de la base de connaissance Lead_tech. Voir `knowledge/frontend/patterns/README.md` pour l'index complet.
|
|
|
|
---
|
|
|
|
<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-link-out-page-locale-canonique"></a>
|
|
## Pattern : Intégration tierce en mode link-out — préférer une page locale canonique
|
|
|
|
### Synthèse
|
|
|
|
- **Objectif** : éviter les parcours concurrents et centraliser les garde-fous UX quand une fonctionnalité publique dépend d'un service tiers externe.
|
|
- **Contexte** : site ou webapp avec CTA publics menant vers un tiers de réservation, paiement, prise de rendez-vous ou formulaire externe.
|
|
- **Quand l'utiliser** : dès qu'une fonctionnalité externe dispose d'une page locale dédiée côté produit (`/reservation`, `/booking`, etc.).
|
|
- **Quand l'éviter** : si le produit assume volontairement une sortie directe unique vers le tiers, sans page locale intermédiaire ni besoin de contextualisation.
|
|
|
|
### Analyse
|
|
|
|
- **Avantages** :
|
|
- UX plus cohérente entre home, navigation et pages dédiées
|
|
- garde-fous, wording et fallbacks centralisés au même endroit
|
|
- facilite l'évolution future vers embed, click-to-load ou variantes de parcours
|
|
- **Limites / vigilance** :
|
|
- ajoute une étape intermédiaire si la page locale n'apporte aucune valeur
|
|
- demande de maintenir l'alignement entre les CTA internes et le parcours canonique
|
|
|
|
### Validation
|
|
|
|
- Validé le : 19-03-2026
|
|
- Contexte technique : site web public / intégration tierce en mode lien externe
|
|
|
|
### Implémentation (exemple minimal)
|
|
|
|
```txt
|
|
- faire pointer les CTA internes (home, nav, landing) vers une page locale dédiée
|
|
- faire de cette page locale le point canonique vers le service tiers externe
|
|
- centraliser sur cette page le contexte utile, les garde-fous et les fallbacks
|
|
- éviter les sorties directes concurrentes vers le tiers depuis plusieurs endroits du site
|
|
```
|
|
|
|
### Checklist
|
|
|
|
- [ ] Un parcours canonique unique est défini
|
|
- [ ] Les CTA internes convergent vers la page locale dédiée
|
|
- [ ] Les garde-fous et fallbacks sont centralisés
|
|
- [ ] Les sorties directes concurrentes vers le tiers sont évitées ou justifiées
|
|
|
|
---
|
|
|
|
<a id="pattern-click-to-load-embeds-tiers"></a>
|
|
## Pattern : Click-to-load strict pour les embeds tiers (iframe/widget)
|
|
|
|
### Synthèse
|
|
|
|
- **Objectif** : ne charger aucun service tiers sans action explicite de l'utilisateur (performance + consentement implicite).
|
|
- **Contexte** : site/webapp avec modules de réservation, map, chat ou tout embed iframe à la demande.
|
|
- **Quand l'utiliser** : dès qu'un embed tiers est chargé à la demande (pas au premier rendu).
|
|
- **Quand l'éviter** : si l'embed est central à la page et doit être visible immédiatement.
|
|
|
|
### Analyse
|
|
|
|
- **Avantages** :
|
|
- LCP non pollué par des tiers (performance-first)
|
|
- Aucun tiers ne reçoit de données utilisateur sans action volontaire (consentement implicite)
|
|
- Fallback toujours disponible en cas d'erreur iframe
|
|
- **Limites / vigilance** :
|
|
- Le fallback (lien externe + `tel:`) doit être actionnable même si l'embed échoue
|
|
|
|
### Validation
|
|
|
|
- Validé le : 21-03-2026
|
|
- Contexte technique : React / Next.js — app-template-resto
|
|
|
|
### Implémentation
|
|
|
|
```tsx
|
|
const [loaded, setLoaded] = useState(false);
|
|
const [errored, setErrored] = useState(false);
|
|
|
|
if (errored) return <a href={url}>Ouvrir {label}</a>;
|
|
|
|
return (
|
|
<>
|
|
{!loaded && <button onClick={() => setLoaded(true)}>Charger {label}</button>}
|
|
{loaded && <iframe src={url} onError={() => setErrored(true)} />}
|
|
</>
|
|
);
|
|
```
|
|
|