Routing
useFlow is framework-agnostic. When your UI is split across routes (one route per step), you’ll typically keep the flow state in useFlow and use your router to show the right screen for the current step.
Route-per-step pattern
Section titled “Route-per-step pattern”In this architecture:
- Your router owns what screen is visible
- useFlow owns what step is current, the path/history, and the context
The simplest integration is one-way sync: when the flow transitions, you navigate.
Expo Router (React Native): one route per step
Section titled “Expo Router (React Native): one route per step”Mount <Flow /> in a stable layout (so it doesn’t unmount between step routes), and use onTransition to navigate.
import { Flow } from "@useflow/react";import { router, Stack } from "expo-router";
import { onboardingFlow } from "@/features/onboarding/flow";
type OnboardingStepId = keyof typeof onboardingFlow.config.steps & string;
function getOnboardingRoute(stepId: OnboardingStepId) { return `/onboarding/${stepId}` as const;}
export default function OnboardingLayout() { return ( <Flow flow={onboardingFlow} onTransition={({ to, direction }) => { const route = getOnboardingRoute(to);
if (direction === "backward") { router.back(); return; }
router.push(route); }} > {() => ( <Stack screenOptions={{ headerShown: false, gestureEnabled: false, animation: "slide_from_right", }} /> )} </Flow> );}Two-way sync (advanced)
Section titled “Two-way sync (advanced)”Most apps only need Flow → Router sync. Two-way sync (Router → Flow) is only needed for advanced cases:
- Deep linking directly to a mid-flow route
- The user navigates via native back/gesture and you want flow
stepId/pathto match - Restoring a persisted flow state and ensuring the router reflects the restored step