useStep()

A simple abstraction to play with a stepper, don't repeat yourself.

The Hook

1import { Dispatch, SetStateAction, useCallback, useMemo, useState } from 'react'
2
3interface Helpers {
4 goToNextStep: () => void
5 goToPrevStep: () => void
6 reset: () => void
7 canGoToNextStep: boolean
8 canGoToPrevStep: boolean
9 setStep: Dispatch<SetStateAction<number>>
10}
11
12type setStepCallbackType = (step: number | ((step: number) => number)) => void
13
14function useStep(maxStep: number): [number, Helpers] {
15 const [currentStep, setCurrentStep] = useState(1)
16
17 const canGoToNextStep = useMemo(
18 () => currentStep + 1 <= maxStep,
19 [currentStep, maxStep],
20 )
21
22 const canGoToPrevStep = useMemo(() => currentStep - 1 >= 1, [currentStep])
23
24 const setStep = useCallback<setStepCallbackType>(
25 step => {
26 // Allow value to be a function so we have the same API as useState
27 const newStep = step instanceof Function ? step(currentStep) : step
28
29 if (newStep >= 1 && newStep <= maxStep) {
30 setCurrentStep(newStep)
31 return
32 }
33
34 throw new Error('Step not valid')
35 },
36 [maxStep, currentStep],
37 )
38
39 const goToNextStep = useCallback(() => {
40 if (canGoToNextStep) {
41 setCurrentStep(step => step + 1)
42 }
43 }, [canGoToNextStep])
44
45 const goToPrevStep = useCallback(() => {
46 if (canGoToPrevStep) {
47 setCurrentStep(step => step - 1)
48 }
49 }, [canGoToPrevStep])
50
51 const reset = useCallback(() => {
52 setCurrentStep(1)
53 }, [])
54
55 return [
56 currentStep,
57 {
58 goToNextStep,
59 goToPrevStep,
60 canGoToNextStep,
61 canGoToPrevStep,
62 setStep,
63 reset,
64 },
65 ]
66}
67
68export default useStep

Usage

1import { useStep } from 'usehooks-ts'
2
3export default function Component() {
4 const [currentStep, helpers] = useStep(5)
5
6 const {
7 canGoToPrevStep,
8 canGoToNextStep,
9 goToNextStep,
10 goToPrevStep,
11 reset,
12 setStep,
13 } = helpers
14
15 return (
16 <>
17 <p>Current step is {currentStep}</p>
18 <p>Can go to previous step {canGoToPrevStep ? 'yes' : 'no'}</p>
19 <p>Can go to next step {canGoToNextStep ? 'yes' : 'no'}</p>
20 <button onClick={goToNextStep}>Go to next step</button>
21 <button onClick={goToPrevStep}>Go to previous step</button>
22 <button onClick={reset}>Reset</button>
23 <button onClick={() => setStep(3)}>Set to step 3</button>
24 </>
25 )
26}

Edit on CodeSandbox

See a way to make this page better?
Edit there »