Anything is better with imagination

XStateSketchnote











const machineConfig = { id: "signInForm", context: { email: "", password: "" }, initial: "ready", states: { ready: { type: "parallel", states: { email: { ...emailStates, }, password: { ...passwordStates, }, authService: { ...authServiceStates, }, }, on: { INPUT_EMAIL: { actions: "cacheEmail", target: "ready.email.noError" }, INPUT_PASSWORD: { actions: "cachePassword", target: "ready.password.noError" }, SUBMIT:[ { cond: "isNoEmail", target: "ready.email.error.empty" }, { cond: "isEmailBadFormat", target: "ready.email.error.badFormat" }, { cond: "isNoPassword", target: "ready.password.error.empty" }, { cond: "isPasswordShort", target: "ready.password.error.tooShort" }, { target: "waitingResponse" } ] }, }, waitingResponse: { on: { CANCEL: "ready" }, invoke: { src: "requestSignIn", onDone: { actions: 'onSuccess' }, onError: [ { cond: "isNoAccount", target: "ready.email.error.noAccount" }, { cond: "isIncorrectPassword", target: "ready.password.error.incorrect" }, { cond: "isNoResponse", target: "ready.authService.error.communication" }, { cond: "isInternalServerErr", target: "ready.authService.error.internal" } ] } }, }, };

const emailStates = { initial: "noError", states: { noError: {}, error: { initial: "empty", states: { empty: {}, badFormat: {}, noAccount: {}, }, onEntry: "focusEmailInput", } } }




const initMachineOptions = ( handleEmailInputFocus, handlePasswordInputFocus, handleSubmitButtonFocus, ) => ({ guards: { isNoEmail: (context, event) => context.email.length === 0, isEmailBadFormat: (context, event) => context.email.length > 0 && !isEmail(context.email), isNoPassword: (context, event) => context.password.length === 0, isPasswordShort: (context, event) => context.password.length < 5, isNoAccount: (context, evt) => evt.data.code === 1, isIncorrectPassword: (context, evt) => evt.data.code === 2, isNoResponse: (context, evt) => evt.data.code === 3, isInternalServerErr: (context, evt) => evt.data.code === 4 }, services: { requestSignIn: (context, event) => signIn(context.email, context.password) }, actions: { focusEmailInput: handleEmailInputFocus, focusPasswordInput: handlePasswordInputFocus, focusSubmitBtn: handleSubmitButtonFocus, cacheEmail: assign((context, event) => ({ email: event.email })), cachePassword: assign((context, event) => ({ password: event.password })), onSuccess: () => { alert("signed in") } }, });

const SignInForm = () => { const signInMachine = Machine(machineConfig, machineOptions) const [current, send] = useMachine(signInMachine) ...

<Textfield name="email" id=“email" ref={emailInputRef} value={current.context.email} onChange={e => { send({ type: “INPUT_EMAIL”, email: e.target.value }) }} disabled={current.matches('waitingResponse')} isRequired autoFocus />

...