useSequentStep
Hook for active step components.
Signature
function useSequentStep<TResult = unknown>(): {
advance: (nextStep: StepLoader, contextPatch?: unknown) => void;
retreat: () => void;
resolve: (value?: TResult) => void;
abort: (reason?: unknown) => void;
context: unknown;
};
StepLoader
type StepLoader = () =>
| ComponentType
| ReactElement
| { default: ComponentType }
| Promise<ComponentType | ReactElement | { default: ComponentType }>;
A step is always passed as a factory:
- Sync factory — returns a component reference immediately
- Element factory — returns JSX directly, useful when async work determines props
- Async factory — returns a promise resolving to a component, JSX element, or
{ default: ComponentType }(matchingimport())
The library normalizes async factories into React.lazy components internally. You never need to call React.lazy yourself.
import Step1 from "./Step1";
// Sync
advance(() => Step1);
// Sync element
advance(() => <Step1 plan="pro" />);
// Async (dynamic import)
advance(() => import("./Step1"));
// Async element after data loading
advance(async () => <Step1 plan={await loadPlan()} />);
Responsibilities
- Move forward with
advance() - Go backward with
retreat() - Finish with
resolve() - Cancel with
abort() - Read flow-scoped
context
Example
function PaymentStep() {
const { advance, context } = useSequentStep();
return (
<button onClick={() => advance(() => ConfirmStep, { plan: context.plan })}>
Continue
</button>
);
}
advance() accepts any StepLoader, including factories that return JSX directly:
advance(async () => {
const quote = await loadQuote();
return <ConfirmStep quote={quote} />;
});
tip
useSequentStep() is only valid inside the active step subtree. Chrome and idle children should use useSequentContext().