State-driven interfaces with XState

Hey đź‘‹

Diky Arga

Frontend Developer di Toserba Online Bukalapak

What's State?

Basically, we as frontend engineer is paid to manage states

A state is a representation of a system in a given time. State refers to the data stored in Application in the form of a string, arrays, object, etc.

ex. is user logged-in? is fetching products? is any filter applied? is product discounted?

How do we manage state?

Example

What could go wrong?

  • What if fetch fails?
  • What if user tap the button twice?
  • What if user want to cancel fetch request?
  • Disable button when fetching
  • Show loading progress
  • Show error message

The problems with

Event Driven Interfaces

  • The code doesn’t accurately represent our component’s intended behavior
    boolean variable like isLoading, isError and isSuccess is hard to manage and error prone
  • Not declarative
  • No separation of concerns

A batter way

State Driven Interfaces

Finite State Machine

FSM

What is?

FSM for developing UI?

XState

 JavaScript state machines and statecharts

by David K Piano

Let's simplify our life

by rewriting our owsem app with state machine

Advantages

  • Declarative (named state, listed all possible state)
  • Easier to test
  • Separation of concerns (view, logic, data fetch)
  • Framework Agnostic
  • Visualization
  • Common language between developer and designer

The cool things about XState

XState Vizualizer

yarn add @xstate/fsm

Only 1 KB

Do we really need library like XState?

No

function dogReducer(state, event) {
  switch (event.type) {
    case "FETCH":
      return {
        ...state,
        status: "loading"
      };
    case "RESOLVE":
      return {
        ...state,
        status: "success",
        dog: event.data
      };
    case "REJECT":
      return {
        ...state,
        status: "failure",
        error: event.error
      };
    case "CANCEL":
      return {
        ...state,
        status: "idle"
      };
    default:
      return state;
  }
}

const initialState = {
  status: "idle",
  dog: null,
  error: null
};

you can use reducer

No

function DogFetcher() {
  // 'idle' or 'loading' or 'success' or 'error'
  const [status, setStatus] = useState('idle');
}

you can use as simple as useState

Already miss isLoading?

function DogFetcher() {
  // 'idle' or 'loading' or 'success' or 'error'
  const [status, setStatus] = useState('idle');

  const isLoading = status === 'loading';

  return (
    // ...
    <button disabled={isLoading}>
      {/* ... */}
    </button>
    // ...
  );
}

Trade-off with State Machine

talkMachine.send('done')

<ThankYou/>

talkMachine.send('QnATime')

references

Made with Slides.com