Skip to content

Counter State Machine

A counter state machine that maintains a numeric value that can be incremented, decremented, and reset, demonstrating how to store and update data within a state.

Unlike the toggle example which uses two distinct states, counter uses a single state (Active) with different data values. Self-transitions preserve the state key but return a new state object with updated data.

import {
createMachine,
defineStates,
setup,
effect,
createStoreMachine,
addStoreApi,
withSubscribe,
} from "matchina";
export const createCounterMachine = () => {
const states = defineStates({
Active: undefined,
Inactive: undefined,
});
const store = createStoreMachine(
{ count: 0 },
{
increment: () => (change) => ({ count: change.from.count + 1 }),
decrement: () => (change) => ({ count: change.from.count - 1 }),
reset: () => () => ({ count: 0 }),
}
);
const storeWithApi = addStoreApi(withSubscribe(store));
const machine = createMachine(
states,
{
Active: {
increment: "Active",
decrement: "Active",
reset: "Active",
deactivate: "Inactive",
},
Inactive: {
activate: "Active",
},
},
"Active"
);
setup(machine)(
effect((ev) => {
if (ev.to.is("Active") && ev.type in storeWithApi.api) {
(storeWithApi.api as any)[ev.type]();
}
})
);
// Encapsulate store and expose methods on machine
const enhancedMachine = Object.assign(machine, {
store: storeWithApi,
increment: () => storeWithApi.api.increment(),
decrement: () => storeWithApi.api.decrement(),
reset: () => storeWithApi.api.reset(),
getCount: () => storeWithApi.getState().count,
});
return enhancedMachine;
};
export type CounterMachine = ReturnType<typeof createCounterMachine>;
  • Storing data within state using the data property
  • Self-transitions that preserve the state key but change the data
  • addEventApi for a clean event-dispatch API