I am trying to build a simple FSM (finite state machine) in ReactJS functional components. I am looking at this which specifies that they it can do it asynchronously and second they may merge the state changes.
In class components, you can chain state changes using the two-argument setState()
method. But that capability is not available in the useState()
hook.
Basically I am wondering because of the behaviour specified is it possible to create an FSM? I am trying to trim the example as small as I can
I am making a few restrictions on my usage of the setter, namely it will only be executed in:
- a state handler function
- an event handler (and even this is limitted)
- a state can have its own substate which is another state store (basically additional parameters that may only be read or written by the two above functions)
Anyway I set my initial state and I have a single useEffect
hook for the state as follows
const [fsmState, setFsmState] = useState(States.Initial)
useEffect(() => {
stateHandlers[fsmState]();
}, [fsmState]);
States
is an enum
enum States {
Initial,
Unauthenticated,
Authenticated,
Processing
}
I define stateHandlers
as follows:
const stateHandlers: {
[key in States]: () => void | Promise<void>;
} = {
[States.Initial]: async () => {
// this may load authentication state from a store,
// for now just set it to Unauthenticated
setFsmState(State.Unauthenticated);
},
[States.SigningIn]: async () => {
const authToken = await loginToServer(signInState));
if (authToken.isValid()) {
setFsmState(State.Authenticated);
} else {
setFsmState(State.Unauthenticated);
}
},
[States.Authenticated]: () => { },
[States.Unauthenticated]: () => { },
}
For the event handler e.g. sign in I do this (which is basically the reason I am asking the question.
const signinAsync = async (username: string, password: string) => {
if (fsmState !== States.Unauthenticated) throw Error("invalid state");
// would these two get set in order?
setSignInState({username,password})
setFsmState(State.SigningIn);
}
As specified earlier, the two-argument version is not available so I cannot do
setSignInState({username,password},
() => { setFsmState(State.SigningIn) } )
I just wanted a simple TSX implementation to avoid adding additional libraries. However, I am still in the midst of coding this as I learn TypeScript/React.
question from:
https://stackoverflow.com/questions/65855083/do-react-state-updates-occur-in-order-when-used-like-an-fsm-and-useeffect