Promise Machine Fetcher
Ready to fetch
Idle
import { createPromiseMachine } from "matchina";
// Function to create a promise machine for fetching dataexport function createPromiseFetcherMachine() { return createPromiseMachine(async (url: string, options?: RequestInit) => { const response = await fetch(url, options); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return response.json(); });}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]); useMachine(fetcher);
const reset = useCallback(() => { setMachineId((id) => id + 1); }, []);
return { machine: fetcher, reset };}import { useState } from "react";
interface FetcherAppViewProps { machine: any; onReset?: () => void;}
export function FetcherAppView({ machine, onReset }: FetcherAppViewProps) { const [url, setUrl] = useState("https://httpbin.org/delay/1"); const state = machine.getState(); const isIdle = state.is("Idle");
return ( <div className="p-5 flex flex-col gap-4"> <div className="flex gap-2 items-center"> <input type="text" value={url} 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" disabled={!isIdle} /> <button onClick={() => machine.execute(url)} disabled={!isIdle} className="btn btn-primary btn-sm shrink-0" > Fetch </button> {!isIdle && ( <button onClick={() => onReset?.()} className="btn btn-ghost btn-sm shrink-0"> Reset </button> )} </div>
<div className="rounded-xl border border-border bg-muted px-4 py-3 min-h-12 flex items-center"> {state.match({ Idle: () => <span className="text-sm text-muted-foreground">Ready to fetch</span>, Pending: ({ params }: any) => ( <span className="text-sm text-muted-foreground animate-pulse"> Fetching {params[0]}… </span> ), 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>
<div className="text-center"> <span className="badge badge-outline text-[10px]">{state.key}</span> </div> </div> );}import { PromiseFetcherView } from "./PromiseFetcherView";import { usePromiseFetcher } from "./hooks";
export function PromiseFetcher() { const { machine, reset } = usePromiseFetcher(); return <PromiseFetcherView machine={machine} onReset={reset} />;}