Traffic Light State Machine
A traffic light state machine that cycles through Red, Yellow, and Green states, demonstrating a state machine with multiple distinct states in a defined sequence.
Implementation Details
Section titled “Implementation Details”This example demonstrates:
- Defining states with typed data using
defineStates()
- Creating a machine with multiple distinct states (Red, Yellow, Green)
- Cyclical transitions between states in a defined sequence
- State-based UI rendering with conditional styling
- Type-safe state handling throughout the application
Unlike the counter example which focuses on state data, or the toggle example with just two states, this traffic light example shows how to model a system with a clear sequence of states and associated messages.
Machine Code
Section titled “Machine Code”import { defineStates, matchina } from "matchina";
const states = defineStates({ Red: () => ({ message: "Stop" }), Yellow: () => ({ message: "Prepare to stop" }), Green: () => ({ message: "Go" }),});
export const createTrafficLightMachine = () => { return matchina( states, { Red: { next: "Green" }, Yellow: { next: "Red" }, Green: { next: "Yellow" }, }, "Red" );};
export type TrafficLightMachine = ReturnType<typeof createTrafficLightMachine>;
import { useMachine } from "matchina/react";import { type TrafficLightMachine } from "./machine";
export const TrafficLightView = ({ machine,}: { machine: TrafficLightMachine;}) => { useMachine(machine); const currentState = machine.getState(); const stateMessage = currentState.data.message; return ( <div className="flex flex-col items-center"> <div className="bg-gray-800 p-4 rounded-lg mb-4"> <div className="flex flex-row space-x-4 items-center"> {/* Red light */} <div className={`w-16 h-16 rounded-full ${ currentState.is("Red") ? "bg-red-600" : "bg-red-900" }`} /> {/* Yellow light */} <div className={`w-16 h-16 rounded-full ${ currentState.is("Yellow") ? "bg-yellow-400" : "bg-yellow-900" }`} /> {/* Green light */} <div className={`w-16 h-16 rounded-full ${ currentState.is("Green") ? "bg-green-500" : "bg-green-900" }`} /> </div> </div>
<div className="text-xl font-bold mb-4">{stateMessage}</div>
<div className="text-sm mb-4"> Current state: <span className="font-mono">{currentState.key}</span> </div>
<button className="px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600" onClick={() => machine.next()} > Next Signal </button> </div> );};
import { useMemo } from "react";import { TrafficLightView } from "./TrafficLightView";import { createTrafficLightMachine } from "./machine";
export function TrafficLightDemo() { const machine = useMemo(createTrafficLightMachine, []); return <TrafficLightView machine={machine} />;}
Additional Notes
Section titled “Additional Notes”- Each state (Red, Yellow, Green) represents a discrete condition of the traffic light
- The
next
transition allows cycling through the states in the proper sequence - The view component uses
state.match()
to elegantly handle different UI states - Pattern matching is type-safe and ensures all states are handled
How This Example Works
Section titled “How This Example Works”This traffic light example demonstrates the core components of a Matchina state machine:
-
State Definition: We define three states (
Red
,Yellow
,Green
), each with associated data (a message).const states = defineStates({Green: () => ({ message: "Go" }),Yellow: () => ({ message: "Prepare to stop" }),Red: () => ({ message: "Stop" }),}); -
Machine Creation: The state machine is created using
matchina()
, which takes:- The defined states
- A transition map describing allowed state changes (using the
next
event) - An initial state (
"Red"
)
return matchina(states,{Green: { next: "Yellow" },Yellow: { next: "Red" },Red: { next: "Green" },},"Red"); -
State Transitions: The machine cycles through states when
machine.next()
is called. -
State Access: The current state is accessed using
machine.getState()
, which provides:- The state key (
currentState.key
) - Type-safe access to state data (
currentState.data.message
) - Methods for state checking (
currentState.is("Red")
)
- The state key (
-
Type Safety: TypeScript ensures type safety throughout, preventing invalid state references.
For a minimal introduction, see the Quick Start.
Extensions
Section titled “Extensions”This basic implementation can be extended in several ways:
- Add automatic transitions using lifecycle hooks and timers
- Implement pedestrian crossing controls
- Add special states like “flashing yellow” for low-traffic periods
Check out the Extended Traffic Light Example to see the first two extensions implemented (automatic transitions and pedestrian crossing).
Next Steps
Section titled “Next Steps”Now that you’ve seen state machines with varying complexity, you might want to explore:
- Matchbox Factories - Learn more about storing and using data in states
- Lifecycle Hooks - Add behavior when states change
- Matchbox Type Inference - Learn about Matchbox type inference