State
useStep
1-indexed step counter for wizards and steppers.
Demo
live · imported from hookli
- step
- 1 / 4
import { useStep } from "hookli";
export function Demo() {
const [step, { goToNextStep, goToPrevStep, canGoToNextStep, canGoToPrevStep, reset }] =
useStep(4);
return (
<div>
<p>Step {step} of 4</p>
<button onClick={goToPrevStep} disabled={!canGoToPrevStep}>Back</button>
<button onClick={goToNextStep} disabled={!canGoToNextStep}>Next</button>
<button onClick={reset}>Reset</button>
</div>
);
}Usage
import { useStep } from "hookli";
export function Demo() {
const [step, { goToNextStep, goToPrevStep, canGoToNextStep, canGoToPrevStep, reset }] =
useStep(4);
return (
<div>
<p>Step {step} of 4</p>
<button onClick={goToPrevStep} disabled={!canGoToPrevStep}>Back</button>
<button onClick={goToNextStep} disabled={!canGoToNextStep}>Next</button>
<button onClick={reset}>Reset</button>
</div>
);
}API
useStep(maxStep: number): [number, UseStepActions]Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| maxStep | number | — | The highest reachable step (inclusive). Steps run from 1 to maxStep. |
Returns
| Name | Type | Description |
|---|---|---|
| [0] step | number | The current step, 1-indexed. |
| [1] actions | UseStepActions | Controls for moving between steps — see below. |
UseStepActions
The second tuple element — the stepper controls.
| Name | Type | Description |
|---|---|---|
| goToNextStep | () => void | Advances to the next step; a no-op at maxStep. |
| goToPrevStep | () => void | Goes back one step; a no-op at step 1. |
| reset | () => void | Resets back to step 1. |
| canGoToNextStep | boolean | Whether a next step is available. |
| canGoToPrevStep | boolean | Whether a previous step is available. |
| setStep | Dispatch<SetStateAction<number>> | Sets the step directly (1-indexed); throws if outside the 1..maxStep range. |
Hook
The implementation, straight from hookli. Copy it, or install the package.
import { Dispatch, SetStateAction, useCallback, useMemo, useState } from "react";
export interface UseStepActions {
goToNextStep: () => void;
goToPrevStep: () => void;
reset: () => void;
canGoToNextStep: boolean;
canGoToPrevStep: boolean;
setStep: Dispatch<SetStateAction<number>>;
}
export const useStep = (maxStep: number): [number, UseStepActions] => {
const [currentStep, setCurrentStep] = useState(1);
const canGoToNextStep = useMemo(
() => currentStep + 1 <= maxStep,
[currentStep, maxStep],
);
const canGoToPrevStep = useMemo(() => currentStep - 1 >= 1, [currentStep]);
const setStep = useCallback<Dispatch<SetStateAction<number>>>(
(step) => {
setCurrentStep((prev) => {
const newStep = step instanceof Function ? step(prev) : step;
if (newStep >= 1 && newStep <= maxStep) {
return newStep;
}
throw new Error("Step not valid");
});
},
[maxStep],
);
const goToNextStep = useCallback(() => {
setCurrentStep((prev) => (prev + 1 <= maxStep ? prev + 1 : prev));
}, [maxStep]);
const goToPrevStep = useCallback(() => {
setCurrentStep((prev) => (prev - 1 >= 1 ? prev - 1 : prev));
}, []);
const reset = useCallback(() => {
setCurrentStep(1);
}, []);
return [
currentStep,
{ goToNextStep, goToPrevStep, canGoToNextStep, canGoToPrevStep, setStep, reset },
];
};