Skip to content

Instantly share code, notes, and snippets.

@lightningspirit
Created September 6, 2022 13:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lightningspirit/d3ce65035930ea61b3f89253fc0df8bd to your computer and use it in GitHub Desktop.
Save lightningspirit/d3ce65035930ea61b3f89253fc0df8bd to your computer and use it in GitHub Desktop.
Preact Hook Finite State Machine
import { useCallback, useEffect, useMemo, useState } from "preact/hooks"
class StateTransitionError extends Error {}
function useFSM<T extends string>(
transitions: Record<T, T[]>,
options: {
throwOnTransitionError?: boolean
} = { throwOnTransitionError: true },
) {
const [startingState] = useMemo(
() => Object.keys(transitions) as unknown as T[],
[transitions],
)
const [currentState, setCurrentState] = useState<T>(startingState)
const reset = useCallback(
function () {
setCurrentState(startingState)
},
[startingState],
)
const canGoToState = useCallback(
function (state: T) {
return transitions[currentState]?.includes(state)
},
[currentState, transitions],
)
const goToState = useCallback(
function (state: T) {
if (!canGoToState(state)) {
if (options.throwOnTransitionError) {
throw new StateTransitionError(
`Cannot perform transition ${currentState} -> ${state}`,
)
}
return false
}
console.log("[state transition]", currentState, "->", state)
setCurrentState(state)
return true
},
[canGoToState, currentState, options.throwOnTransitionError],
)
return {
reset,
goToState,
canGoToState,
state: currentState,
}
}
export default useFSM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment