✈ 🚀 🔭 🌌
💻
W T F?
Mathematical model
Single explicitness source
Useful for modeling states
Finite amount of states
Starts from one of them
Transitions between them only by events
Executes side effects on transitions
state
state
event
event
event
event
I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea.
Data binding
(unidirectional, bidirectional)
element.addEventListener("click", clickHandler);
channel.on("message", readMessage);
type State = {
isLoading: boolean;
accounts: Account[];
error?: any;
};
type State =
| "Idle"
| "Loading"
| "Success"
| "Error";
We're acustomed to
in the FSM world
const remoteDataState =
| "Idle"
| "Pending"
| "Success"
| "Error"
const remoteDataState = {
isPending: boolean;
}
const formState =
| Idle
| Touched
| Validating
| Submitting
const formState = {
isTouched: boolean;
isValidating: boolean;
isSubmitting: boolean;
}
const formState = {
initialState: "idle",
states: {
idle: {
on: {
INPUT_FOCUS: "touched"
}
},
touched: {
on: {
INPUT_CHANGE: "validating"
}
}
}
}
{
initial: "idle",
states: {
idle: {
on: {
TYPE: "readyToSearch"
}
},
readyToSearch: {
on: {
SUBMIT: "searching"
}
},
submitting: {
on: {
SEARCH_SUCCESS: "itemsRendered",
SEARCH_FAILURE: "errorShown"
}
}
}
}
Search
Search
Pizza and Beer
Onboarding new developers
Understanding legacy code
Faster feature iterations
Robust debugging
Cross Competence communication
function HeadlessCarousel(props) {
const {children, ...carouselProps} = props;
const [state, sendEvent] = useMachine(carouselProps);
return children({
state: state.value,
data: state.context,
next() {
sendEvent("NEXT")
},
prev() {
sendEvent("PREV")
},
play() {
sendEvent("PLAY");
},
pause() {
sendEvent("PAUSE")
}
})
}
<HeadlessCarousel>
{headlessCarousel => {
<div>
<button onClick={headlessCarousel.next}>
Next
</button>
</div>
}}
</HeadlessCarousel>
<HeadlessCarousel>
{headlessCarousel => {
<View>
<TouchableOpacity onPress={headlessCarousel.next}>
Next
</TouchableOpacity>
</View>
}}
</HeadlessCarousel>
stdin.on("keypress", (_, code) => {
if (code === ARROW_RIGHT) {
sendEvent("NEXT");
}
});
State Explosion
Conditional transitions
Conditional side effects
State Structure
extends FSM
Make Nested machines
Make Parallel Machines
Conditional Transitions
Store Non-concrete state
&& data
Things can happen only if other things have happened before
Things can live independently in the same context
Guard against invalidity / Branching logic
Model non-concrete concepts e.g. Animations / Internal data store
Submit form only after the input is validated
Twitter Feed vs Side Widget
Red input when invalid / Green input when valid
Battery percentage / List of countries / Server Error
State Structure
Support Entry Actions
Support Exit Actions
Actions to be executed when you enter a state (Good for initializing stuff)
Actions to be executed when you exit a state (Good for cleaning up)
Start off a fetch controller upon entering the pending state
Cancel the fetch upon exiting pending state
Different type of
Side Effects
Fire and Forget, invoking async tasks, activities, streams, etc
Any state is worth a State Machine
State Machines bring up implicit / hidden / missing states to the surface
State Machines follow a (state, event) >> action
State Machines are easier to reason about
State Machines consider the dimension of time
#GDG #Elisa