1.0.1 • Published 26 days ago

trido95-xstate-react v1.0.1

Weekly downloads
-
License
-
Repository
-
Last release
26 days ago

State Machine

This is simple state for logic use to xstate lib

Install

npm i trido95-xstate-react@latest

Usage

  1. First, declare the types to use the state machine according to the specified rules.
/**
 * type.ts
 */
export type TContext = {
  profile: {
    userName: string;
    fullName: string;
  };
  userName: string;
  passWord: string;
};
export type TEvent = {
  type: "SET_USERNAME" | "SET_PASSWORD" | "LOGIN";
};
export type TState = "login" | "connect" | "done" | "error";
  1. Next, create a desired scenario. This scenario will be your logical construction, helping to build the login (UX) separately from the view (UI) quickly and efficiently, making it easy to apply and reuse.
  2. Some notes as follows: Config is a function for you to use to create the scenario. Objects such as actions, guards, and services are there for you to write and test your logic.
/** logic.ts */
import { Config, assign, createStateMachine } from "baotri95.dev/machine";
import { TEvent, TState, TContext } from "type";
const services = {
  apiLogin: async (context) => await "call api",
};
const actions = {
  // logic function
  // example
  setPass: assign({
    passWord: (ctx, e) => e.passWord,
  }),}
};
const guards = {
  // validate function
  checkEmpty: (ctx) => ctx.userName.length && ctx.passWord.length
};
const stateConfig = Config<TContext, TState, TEvent>({
  id: "login",
  context: {
    profile: {
      userName: "",
      fullName: "",
    },
    userName: "",
    passWord: "",
  },
  initial: "login",
  states: {
    login: {
      on: {
        SET_USERNAME: {
          actions: assign({
            userName: (ctx, e) => e.userName, // ,
          }),
        },
        SET_PASSWORD: {
          actions: ['setPass'] // call setPasss to actions, actions is string, array or a function concept. ('setPass', ['setPass', 'setPass1'])
        },
        LOGIN: {
          target: "connect",
          cond: 'checkEmpty' // call checkEmpty to guards
        },
      },
    },
    connect: {
      invoike: {
        src: "apiLogin",
        onDone: {
          target: "done",
          actions: assign({
            profile: (ctx, e) => e.data,
          }),
        },
        onError: {
          target: "error",
        },
      },
    },
    done: {},
    error: {},
  },
});
export const LoginMachine = () => createStateMachine<TContext, TEvent>(config, {
  services,
  actions,
  guards,
});
  1. Finally, create the UI (ReactJS) to effectively use the state machine. Good luck!
/**
 * Login.tsx
 */
import { LoginMachine } from "logic";

export function Login() {
  const LoginState = LoginMachine()
  const context = LoginState.context;
  return (<div>
     {
     LoginState.matches('login') &&
      <div>
       <div> <h5>Login</h5></div>
        <div>
         <label>User Name</label>
          <input name="userName" onChange={e => LoginState.sendEvent('SET_USERNAME', {userName: e.target.userName})}/>
        <div>
       <div>
        <label>User Name</label>
         <input name="passWord" onChange={e => LoginState.sendEvent('SET_PASSWORD', {passWord: e.target.passWord})}/>
        <div>
        <div>
              <button onClick={LoginState.sendEvent('LOGIN')}>LOGIN</button>
        </div>
    </div>
  }
  {
 LoginState.matches('done') &&
    <div>
       <div>Profile</div>
       <div>{context.profile.fullName}</div>
    </div>
     }
  </div>)
  ;
}

The structure of the state machine to use

logic/
  type.ts
  actions.ts
  guards.ts
  services.ts
  state.ts
  index.ts
view/
  index.tsx