Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
November 26, 2020 07:30 am GMT

React State Machine Hook

This custom hook is meant to live somewhere in between the built-in useReducer and pulling in a 3rd party library like xstate.

let { state, status } = useStateMachine(    stateChart,     initialState,     updaters,    transitionEffects?);
Enter fullscreen mode Exit fullscreen mode

It's not quite useful/big enough to warrant an NPM package, so I created a code snippet and will document it here for the next time I reach for it.

1. Document the State and available Statuses

The State Machine will track 2 things,

  1. status - the State Machine's state, called status to avoid confusing with React state.
  2. state - The stateful data that should be tracked in addition to status. This is just like the state for useReducer.
export interface AuthState {  error: string;  currentUser: {     uid: string;     name: string;     email: string   };}const initialState: AuthState = {  currentUser: null,  error: ""};export type AuthStatus =  | "UNKNOWN"  | "ANONYMOUS"  | "AUTHENTICATING"  | "AUTHENTICATED"  | "ERRORED";
Enter fullscreen mode Exit fullscreen mode

2. Create the State Chart

For each status, what actions can be performed? If that action runs, to which status should it transition?

The names of the actions should match the names of the updaters in the next step.

const stateChart: StateChart<AuthStatus, typeof updaters> = {  initial: "UNKNOWN",  states: {    UNKNOWN: {      setCachedUser: "AUTHENTICATED",      logout: "ANONYMOUS",      handleError: "ERRORED"    },    ANONYMOUS: {      loginStart: "AUTHENTICATING"    },    AUTHENTICATING: {      loginSuccess: "AUTHENTICATED",      handleError: "ERRORED"    },    AUTHENTICATED: {      logout: "ANONYMOUS"    },    ERRORED: {      loginStart: "AUTHENTICATING"    }  }};
Enter fullscreen mode Exit fullscreen mode

3. Implement the State Updaters

A state updater is a function that takes in the current state (a React state) and the triggered action, then returns the updated state. Just like a reducer.

(state, action) => updatedState

  • Some actions are triggered just to cause a State Machine status transition, like loginStart. In this case, just return the state right back.
  • The names of the updaters should match the names of the actions in the State Chart.
const updaters = {  loginSuccess: (state, { user }) => {    cacheCurrentUser(user);    return {      error: "",      currentUser: user    };  },  setCachedUser: (state, { user }) => {    return {      error: "",      currentUser: user    };  },  logout: (state) => {    cacheCurrentUser(null);    return {      error: "",      currentUser: null    };  },  handleError: (state, { error }) => {    return {      ...state,      error: error.message    };  },  loginStart: (state, { username, password }) => state};
Enter fullscreen mode Exit fullscreen mode

4. Use and Define Transition Effects

The last step is to use the hook.

You can also define effect functions to be run when the state machine transitions into a specified state. This is useful for doing async work.

The enter transition is given the action that caused the transition as well as all the available actions.

In this example, when the user calls, loginStart, the status will transition to AUTHENTICATING, which will trigger the transition to call api.login. Based on the result of login(), either the success or error action is triggered.

function useAuth() {  let stateMachine = useStateMachine(stateChart, initialState, updaters, {    AUTHENTICATING: {      enter: async ({ action, actions }) => {        try {          let user = await api.login({            username: action.username,            password: action.password          });          actions.loginSuccess({ user });        } catch (error) {          actions.handleError({ error });        }      }    },    UNKNOWN: {      enter: () => {        let cachedUser = getCurrentUserFromCache();        if (cachedUser && cachedUser.token) {          stateMachine.actions.setCachedUser({ user: cachedUser });        } else {          stateMachine.actions.logout();        }      }    }  });  return stateMachine;}
Enter fullscreen mode Exit fullscreen mode

Original Link: https://dev.to/droopytersen/state-machine-hook-hdg

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To