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> );}Start from a route-specific step
Section titled “Start from a route-specific step”When your app decides the initial route before the flow mounts, pass that step as initialStepId:
<Flow flow={onboardingFlow} initialStepId={initialRouteStepId} onTransition={({ to }) => { router.push(getOnboardingRoute(to)); }}> {() => <Stack screenOptions={{ headerShown: false }} />}</Flow>initialStepId is an entry-point override for fresh flow state. If a persister restores valid saved state, useFlow restores the saved step instead.
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