# Frontend — Patterns : Navigation > Extrait de la base de connaissance Lead_tech. Voir `knowledge/frontend/patterns/README.md` pour l'index complet. --- ## 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 --- ## 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 --- ## 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 Ouvrir {label}; return ( <> {!loaded && } {loaded &&