const [state, send] = useStateMachine({
initial: "enabled",
states: {
enabled: {
on: { TOGGLE: "disabled" },
},
disabled: {
on: { TOGGLE: "enabled" },
},
},
});
npm install @rkrupinski/use-state-machine
Examples
const [
state, // <--- this guy
send,
] = useStateMachine(/* ... */);
state
is an object of the following shape:Name | Description |
---|---|
value
|
Type: string
The name of the current state. |
nextEvents
|
Type: string[]
The names of possible events. (see Events) |
event
|
Type: Event
The event that led to the current state. (see Events) |
context
|
Type: C (inferred)
Machine's extended state. Think of it as a place to store additional, machine-related data throughout its whole lifecycle. (see Context) |
const [
state,
send, // <--- this guy
] = useStateMachine(/* ... */);
send
function.Name | Description |
---|---|
send
|
Type: (event: string | Event) => void
|
string
) syntax:send("START");
Event
) syntax:send({ type: "START" });
Event
).type
, can also carry payload
.const [state, send] = useStateMachine({
initial: "idle",
states: {
/* ... */
},
context: 42,
});
Name | Description |
---|---|
initial (required)
|
Type: string
The initial machine state value. ℹ️ Note: Must be a key of states
|
states (required)
|
Type: { [key: string]: StateConfig }
An object with configuration for all the states. (see Configuring states) |
context
|
Type: C
Initial context value. ℹ️ Note: Used for inferring context type. (see Context) |
states
field of the machine options.const [state, send] = useStateMachine({
/* ... */
states: {
idle: {
on: {
START: "running",
},
effect() {
console.log("idling");
},
},
/* ... */
},
});
states
object are state names, values are StateConfig
object of the following shape:Name | Description |
---|---|
on
|
Type: { [key: string]: string | EvtConfig }
An object with configuration for all the transitions supported by this particular state. (see Configuring state transitions) |
effect
|
Type: Effect
A callback fired once the machine has transitioned to this particular state. (see Effects) |
effect
field.const [state, send] = useStateMachine({
/* ... */
states: {
idle: {
effect({ context, setContext, event, send }) {
console.log("idling due to", event.type);
return () => {
console.log("idling no more");
};
},
},
/* ... */
},
});
effect
callback will receive an object of the following shape:Name | Description |
---|---|
context
|
Type: C (inferred)
The current value of the machine context. (see Context) |
setContext
|
Type: (updater: (context: C) => C) => void
A function to update the value of context .
(see Context) |
event
|
Type: Event
The event that led to the current state. (see Events) |
send
|
Type: (event: string | Event) => void
A function to send events to the machine. (see Events) |
effect
is of type function
, that function will be executed when the machine transitions away from the current state (exit/cleanup effect):effect() {
console.log('entered a state');
return () => {
console.log('exited a state');
};
},
send("ONE");
send("TWO");
send("THREE");
THREE
(if defined) will be executed.on
property of StateConfig
.const [state, send] = useStateMachine({
/* ... */
states: {
idle: {
on: {
START: "running",
FUEL_CHECK: {
target: "off",
guard() {
return isOutOfFuel();
},
},
},
},
off: {},
},
});
string
(denoting the target state value) or an object of the following shape:Name | Description |
---|---|
target (required)
|
Type: string
Target state value. ℹ️ Note: Must be a key of states .
(see Configuring states) |
guard
|
Type: Guard
A boolean -returning function to determine whether state transition is allowed.
(see Guards) |
guard
function is invoked before performing state transition and depending on its return value:true
➡️ transition is performedfalse
➡️ transition is preventedguard
function will receive an object of the following shape:Name | Description |
---|---|
event
|
Type: Event
The event that triggered state transition. (see Events) |
context
|
Type: C (inferred)
The current value of the machine context. (see Context) |
Event
) syntax, you can send events with payload like so:send({
type: "REFUEL",
payload: { gallons: 5 },
});
state
object (see State)effect
functions (see Effects)guard
functions (see Guards)payload
inferred correctly?event.payload
) is always typed as unknown
and it's up to the consumer to extract all the required information from it.guard
function that only allows refueling if the number of gallons is at least 5
, using io-ts to decode the payload
:import * as t from "io-ts";
import { pipe } from 'fp-ts/function';
import { fold } from 'fp-ts/Either';
const RefuelPayload = t.type({
gallons: t.number,
});
/* ... */
guard({ event }) {
const gallons = pipe(
RefuelPayload.decode(event.payload),
fold(
() => 0,
p => p.gallons,
),
);
return gallons >= 5;
}
Context
context
is inferred from the initial value (see Machine options).42
➡️ number
'context'
➡️ string
[1, 2, 3]
➡️ number[]
'foo'
vs string
){ foo?: string }
)'foo' | 'bar'
)context
.type ContextType = "foo" | "bar";
const [state, send] = useStateMachine({
/* ... */
context: "foo" as ContextType,
});
state.context; // 'foo' | 'bar'
GitHub