import { useEffect, useState } from "react"; import { MemoryRouter } from "./MemoryRouter"; export type MemoryRouterEventHandlers = { onHashChangeStart?: (url: string, options: { shallow: boolean }) => void; onHashChangeComplete?: (url: string, options: { shallow: boolean }) => void; onRouteChangeStart?: (url: string, options: { shallow: boolean }) => void; onRouteChangeComplete?: (url: string, options: { shallow: boolean }) => void; onPush?: (url: string, options: { shallow: boolean }) => void; onReplace?: (url: string, options: { shallow: boolean }) => void; }; export const useMemoryRouter = (singletonRouter: MemoryRouter, eventHandlers?: MemoryRouterEventHandlers) => { const [router, setRouter] = useState(() => MemoryRouter.snapshot(singletonRouter)); // Trigger updates on route changes: useEffect(() => { // To ensure we don't call setRouter after unmounting: let isMounted = true; const handleRouteChange = () => { if (!isMounted) return; // Ensure the reference changes each render: setRouter(MemoryRouter.snapshot(singletonRouter)); }; singletonRouter.events.on("routeChangeComplete", handleRouteChange); singletonRouter.events.on("hashChangeComplete", handleRouteChange); return () => { isMounted = false; singletonRouter.events.off("routeChangeComplete", handleRouteChange); singletonRouter.events.off("hashChangeComplete", handleRouteChange); }; }, [singletonRouter]); // Subscribe to any eventHandlers: useEffect(() => { if (!eventHandlers) return; const { // onRouteChangeStart, onRouteChangeComplete, onHashChangeStart, onHashChangeComplete, onPush, onReplace, } = eventHandlers; if (onRouteChangeStart) singletonRouter.events.on("routeChangeStart", onRouteChangeStart); if (onRouteChangeComplete) singletonRouter.events.on("routeChangeComplete", onRouteChangeComplete); if (onHashChangeStart) singletonRouter.events.on("hashChangeStart", onHashChangeStart); if (onHashChangeComplete) singletonRouter.events.on("hashChangeComplete", onHashChangeComplete); if (onPush) singletonRouter.events.on("NEXT_ROUTER_MOCK:push", onPush); if (onReplace) singletonRouter.events.on("NEXT_ROUTER_MOCK:replace", onReplace); return () => { if (onRouteChangeStart) singletonRouter.events.off("routeChangeStart", onRouteChangeStart); if (onRouteChangeComplete) singletonRouter.events.off("routeChangeComplete", onRouteChangeComplete); if (onHashChangeStart) singletonRouter.events.off("hashChangeStart", onHashChangeStart); if (onHashChangeComplete) singletonRouter.events.off("hashChangeComplete", onHashChangeComplete); if (onPush) singletonRouter.events.off("NEXT_ROUTER_MOCK:push", onPush); if (onReplace) singletonRouter.events.off("NEXT_ROUTER_MOCK:replace", onReplace); }; }, [ singletonRouter.events, eventHandlers?.onRouteChangeStart, eventHandlers?.onRouteChangeComplete, eventHandlers?.onHashChangeStart, eventHandlers?.onHashChangeComplete, eventHandlers?.onPush, eventHandlers?.onReplace, ]); return router; };