Skip to content

Hook API

function useStateChart<TContext, TEvent>(
chartOrInstance: Chart | ChartInstance,
options?: UseStateChartOptions
): UseStateChartReturn;

chartOrInstance

Pass either a Chart or ChartInstance:

  • Chart: Hook creates and manages the instance lifecycle (starts on mount, stops on unmount)
  • ChartInstance: Hook subscribes only; you manage the lifecycle
// Chart - hook manages lifecycle
const { state, send } = useStateChart(myChart);
// ChartInstance - you manage lifecycle
const instance = myChart.start();
const { state, send } = useStateChart(instance);
interface UseStateChartOptions<TContext> {
initialContext?: Partial<TContext>;
onTransition?: (prev: IStateSnapshot, next: IStateSnapshot) => void;
}
OptionTypeDescription
initialContextPartial<TContext>Override initial context (ignored for ChartInstance)
onTransition(prev, next) => voidCallback after each state transition
interface UseStateChartReturn<TContext, TEvent> {
state: IStateSnapshot<TContext>;
send: (event: TEvent | TEvent["type"]) => void;
matches: (stateValue: string) => boolean;
}
const counter = chart({
context: { count: 0 },
initial: "idle",
states: {
idle: {
on: {
INCREMENT: { actions: (ctx) => ({ count: ctx.count + 1 }) },
},
},
},
});
function Counter() {
const { state } = useStateChart(counter, {
initialContext: { count: 100 }, // Start at 100 instead of 0
});
return <span>{state.context.count}</span>;
}
function Toggle() {
const { state, send } = useStateChart(toggle, {
onTransition: (prev, next) => {
console.log(`State changed: ${prev.value}${next.value}`);
analytics.track("state_change", { from: prev.value, to: next.value });
},
});
return <button onClick={() => send("TOGGLE")}>{state.value}</button>;
}

Share state across multiple components:

// Create instance outside components
const sharedInstance = authChart.start();
function LoginButton() {
const { send, matches } = useStateChart(sharedInstance);
if (matches("authenticated")) {
return <button onClick={() => send("LOGOUT")}>Logout</button>;
}
return <button onClick={() => send("LOGIN")}>Login</button>;
}
function UserProfile() {
const { state, matches } = useStateChart(sharedInstance);
if (!matches("authenticated")) {
return null;
}
return <div>Welcome, {state.context.user.name}</div>;
}

The hook infers types from the chart definition:

const { state, send } = useStateChart(counter);
state.context.count; // number
state.value; // "idle"
send("INCREMENT"); // OK
send("INVALID"); // Type error