@shopify/hydrogen-react
Version:
React components, hooks, and utilities for creating custom Shopify storefronts
69 lines (68 loc) • 1.93 kB
JavaScript
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