Skip to content

Stopwatch with External React State

This example demonstrates a state machine with external React state management:

  • Uses React’s useState to manage the elapsed time outside the machine
  • Connects the external state to the machine via props
  • Implements effects as functions that can access and modify the external state
  • Uses utility hooks for state and event effects

This pattern is particularly useful when you need to:

  1. Integrate with existing React state management
  2. Share state across multiple components
  3. Keep state management separate from the state machine logic
import { createMachine, defineStates, assignEventApi } from "matchina";
import { tickEffect } from "../lib/tick-effect";
export const createStopwatchMachine = (
elapsed: number,
setElapsed: (elapsed: number) => void
) => {
const effects = {
clear: () => setElapsed(0),
run: () => {
let lastTick = Date.now();
return tickEffect(() => {
const now = Date.now();
setElapsed(stopwatch.elapsed + now - lastTick);
lastTick = now;
});
},
};
const states = defineStates({
Stopped: { effects: [effects.clear] },
Ticking: { effects: [effects.run] },
Suspended: {},
});
const stopwatch = Object.assign(
assignEventApi(
createMachine(
states,
{
Stopped: {
start: "Ticking",
},
Ticking: {
stop: "Stopped",
suspend: "Suspended",
clear: "Ticking",
},
Suspended: {
stop: "Stopped",
resume: "Ticking",
clear: "Suspended",
},
},
"Stopped"
)
),
{
elapsed,
effects,
}
);
return stopwatch;
};