Files
MaksTinyWorkshop 9b7af9f1b0 Refonte Structure
2026-03-25 08:34:19 +01:00

6.1 KiB

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)

// ❌ 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)

// 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

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)

- 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

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)} />}
  </>
);