A simple HTTP fetcher built with promise machines, demonstrating how to handle asynchronous operations with automatic state management for loading, success, and error states.
import { createPromiseMachine } from "matchina" ;
// Function to create a promise machine for fetching data
export function createPromiseFetcherMachine () {
return createPromiseMachine ( async ( url : string , options ?: RequestInit ) => {
const response = await fetch (url, options);
throw new Error ( `HTTP ${ response . status }: ${ response . statusText }` );
import { useMachine } from "matchina/react" ;
import { useMemo, useState, useCallback } from "react" ;
import { createPromiseFetcherMachine } from "./machine" ;
export function usePromiseFetcher () {
const [ machineId , setMachineId ] = useState ( 0 );
const fetcher = useMemo (() => createPromiseFetcherMachine (), [machineId]);
const reset = useCallback (() => {
setMachineId (( id ) => id + 1 );
return { machine: fetcher, reset };
import { useState } from "react" ;
interface FetcherAppViewProps {
export function FetcherAppView ({ machine , onReset } : FetcherAppViewProps ) {
const [ url , setUrl ] = useState ( "https://httpbin.org/delay/1" );
const state = machine. getState ();
const isIdle = state. is ( "Idle" );
< div className = "p-5 flex flex-col gap-4" >
< div className = "flex gap-2 items-center" >
onChange = {( e ) => setUrl (e.target.value)}
className = "flex-1 px-3 py-1.5 rounded-lg border border-border bg-muted text-sm min-w-0 focus:outline-none focus:ring-2 focus:ring-ring"
placeholder = "Enter URL to fetch"
onClick = {() => machine. execute (url)}
className = "btn btn-primary btn-sm shrink-0"
< button onClick = {() => onReset ?.()} className = "btn btn-ghost btn-sm shrink-0" >
< div className = "rounded-xl border border-border bg-muted px-4 py-3 min-h-12 flex items-center" >
Idle : () => < span className = "text-sm text-muted-foreground" >Ready to fetch</ span >,
Pending : ({ params } : any ) => (
< span className = "text-sm text-muted-foreground animate-pulse" >
Resolved : ( _data : any ) => (
< span className = "text-sm font-medium text-[oklch(0.55_0.16_142)]" >Success!</ span >
Rejected : ( error : any ) => (
< span className = "text-sm font-medium text-destructive" >Error: {error.message}</ span >
< div className = "text-center" >
< span className = "badge badge-outline text-[10px]" >{state.key}</ span >
import { PromiseFetcherView } from "./PromiseFetcherView" ;
import { usePromiseFetcher } from "./hooks" ;
export function PromiseFetcher () {
const { machine , reset } = usePromiseFetcher ();
return < PromiseFetcherView machine = {machine} onReset = {reset} />;
Promise machines automatically transition between states based on the fetch lifecycle:
Idle — ready to make a request
Pending — request in flight, shows loading state
Resolved — request succeeded, displays response data
Rejected — request failed, shows error message
The reset functionality recreates the machine instance by incrementing a machineId, forcing React to mount a fresh machine in the Idle state.
import { createPromiseMachine } from "matchina" ;
// Function to create a promise machine for fetching data
export function createPromiseFetcherMachine () {
return createPromiseMachine ( async ( url : string , options ?: RequestInit ) => {
const response = await fetch (url, options);
throw new Error ( `HTTP ${ response . status }: ${ response . statusText }` );