State-driven interfaces with XState
Hey đź‘‹
Diky Arga
Squad Search EXperience 🔍

What's State?
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 Loading?, is Error? is Wahyudi?

Basically, we as a frontend dev is getting paid to manage states
isLoading?
isError?
isAbela?
How do we manage state?

basic fetch and set the data



loading lama, tambah loading bar
kadang error, tampilin error message
user plin-plan, mau batalin request

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
- What if request is restricted/blocked?
- and so on..
The problems with
Event Driven Interfaces
- The code doesn’t accurately represent our component’s intended behavior
boolean variable like isLoading, isError, isSuccess, isMail is hard to manage and error prone - Not declarative
what to do with isSuccess? - No separation of concerns
nasi ruwet code in a component
A batter way (hopefully)
State Driven Interfaces
Finite State Machine
FSM
What is?

FSM is everywhere



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
Statedriven interfaces with XState at BL
By Diky Arga
Statedriven interfaces with XState at BL
- 493