UNPKG

@shopify/hydrogen-react

Version:

React components, hooks, and utilities for creating custom Shopify storefronts

69 lines (68 loc) 1.93 kB
import { interpret, createMachine, InterpreterStatus } from "@xstate/fsm"; import { useRef, useCallback, useSyncExternalStore, useEffect, useLayoutEffect } from "react"; const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect; function useConstant(fn) { const ref = useRef(); if (!ref.current) { ref.current = { v: fn() }; } return ref.current.v; } function getServiceState(service) { let currentValue; service.subscribe((state) => currentValue = state).unsubscribe(); return currentValue; } function useMachine(stateMachine, options) { const persistedStateRef = useRef(); const [service, queue] = useConstant(() => { const eventQueue = []; const svc = interpret( createMachine( stateMachine.config, options ? options : stateMachine._options ) ); const originalSend = svc.send; svc.send = (event) => { if (svc.status === InterpreterStatus.NotStarted) { eventQueue.push(event); return; } originalSend(event); persistedStateRef.current = svc.state; }; return [svc, eventQueue]; }); useIsomorphicLayoutEffect(() => { if (options) { service._machine._options = options; } }); const getSnapshot = useCallback(() => getServiceState(service), [service]); const subscribe = useCallback( (handleStoreChange) => { const { unsubscribe } = service.subscribe(handleStoreChange); return unsubscribe; }, [service] ); const storeSnapshot = useSyncExternalStore( subscribe, getSnapshot, getSnapshot ); useEffect(() => { service.start(persistedStateRef.current); queue.forEach(service.send); persistedStateRef.current = service.state; return () => { service.stop(); }; }, []); return [storeSnapshot, service.send, service]; } export { useMachine }; //# sourceMappingURL=useMachine.mjs.map