useStep
A hook that allows to manage and navigate between steps in a sequence.
Example
import clsx from "clsx";
import useStep from "@/hooks/useStep";
export default function UseStepExample() {
const [currentStep, helpers] = useStep(5);
const {
canGoToPrevStep,
canGoToNextStep,
goToNextStep,
goToPrevStep,
reset,
setStep,
} = helpers;
return (
<div className="flex flex-col items-center justify-center gap-4 text-ctp-text">
<p>
Current step is <strong>{currentStep}</strong>
</p>
<div className="flex gap-4">
<p>
Can go to previous step{" "}
<span
className={clsx(
"rounded p-2 text-ctp-base",
canGoToPrevStep ? "bg-ctp-green" : "bg-ctp-red",
)}
>
{canGoToPrevStep ? "yes" : "no"}
</span>
</p>
<p>
Can go to next step{" "}
<span
className={clsx(
"rounded p-2 text-ctp-base",
canGoToNextStep ? "bg-ctp-green" : "bg-ctp-red",
)}
>
{canGoToNextStep ? "yes" : "no"}
</span>
</p>
</div>
<div className="flex gap-4">
<button
className="rounded bg-ctp-blue px-4 py-2 text-ctp-base"
onClick={goToNextStep}
>
Go to next step
</button>
<button
className="rounded bg-ctp-pink px-4 py-2 text-ctp-base"
onClick={goToPrevStep}
>
Go to previous step
</button>
<button
className="rounded bg-ctp-red px-4 py-2 text-ctp-base"
onClick={reset}
>
Reset
</button>
<button
className="rounded bg-ctp-yellow px-4 py-2 text-ctp-base"
onClick={() => {
setStep(3);
}}
>
Set to step 3
</button>
</div>
</div>
);
}
Code
import { useCallback, useState } from "react";
import type { Dispatch, SetStateAction } from "react";
type UseStepActions = {
goToNextStep: () => void;
goToPrevStep: () => void;
reset: () => void;
canGoToNextStep: boolean;
canGoToPrevStep: boolean;
setStep: Dispatch<SetStateAction<number>>;
};
type SetStepCallbackType = (step: number | ((step: number) => number)) => void;
type UseStepReturn = [number, UseStepActions];
/**
* A hook that allows to manage and navigate between steps in a sequence.
* @param {number} maxStep - The maximum step value.
* @returns {UseStepReturn} An array containing the current step value and an object with the following properties:
* 1. goToNextStep - A function to go to the next step.
* 2. goToPrevStep - A function to go to the previous step.
* 3. canGoToNextStep - A boolean indicating whether the next step is available.
* 4. canGoToPrevStep - A boolean indicating whether the previous step is available.
* 5. setStep - A function to set the step value.
* 6. reset - A function to reset the step value to 1.
*/
export default function useStep(maxStep: number): UseStepReturn {
const [currentStep, setCurrentStep] = useState(1);
const canGoToNextStep = currentStep + 1 <= maxStep;
const canGoToPrevStep = currentStep - 1 > 0;
const setStep = useCallback<SetStepCallbackType>(
(step) => {
// Allow value to be a function so we have the same API as useState
const newStep = step instanceof Function ? step(currentStep) : step;
if (newStep >= 1 && newStep <= maxStep) {
setCurrentStep(newStep);
return;
}
throw new Error("Step not valid");
},
[maxStep, currentStep],
);
const goToNextStep = useCallback(() => {
if (canGoToNextStep) {
setCurrentStep((step) => step + 1);
}
}, [canGoToNextStep]);
const goToPrevStep = useCallback(() => {
if (canGoToPrevStep) {
setCurrentStep((step) => step - 1);
}
}, [canGoToPrevStep]);
const reset = useCallback(() => {
setCurrentStep(1);
}, []);
return [
currentStep,
{
goToNextStep,
goToPrevStep,
canGoToNextStep,
canGoToPrevStep,
setStep,
reset,
},
];
}