diff --git a/apps/dashboard/src/@/lib/DashboardRouter.tsx b/apps/dashboard/src/@/lib/DashboardRouter.tsx index 971a02def37..3e15b850aff 100644 --- a/apps/dashboard/src/@/lib/DashboardRouter.tsx +++ b/apps/dashboard/src/@/lib/DashboardRouter.tsx @@ -1,75 +1,64 @@ "use client"; // eslint-disable-next-line no-restricted-imports -import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { useRouter } from "next/navigation"; import { - Suspense, + type TransitionStartFunction, useEffect, useMemo, useRef, useState, useSyncExternalStore, + useTransition, } from "react"; import { createStore } from "./reactive"; // Using useDashboardRouter instead of useRouter gives us a nice progress bar on top of the page when navigating using router.push or router.replace -// using a store instead of context to avoid triggering re-renders on root component -const LoadingRouteHref = createStore(undefined); +const RouteStartTransitionFn = createStore((fn) => + fn(), +); export function useDashboardRouter() { + const startTransition = useSyncExternalStore( + RouteStartTransitionFn.subscribe, + RouteStartTransitionFn.getValue, + RouteStartTransitionFn.getValue, + ); + const router = useRouter(); return useMemo(() => { return { ...router, replace(href: string, options?: { scroll?: boolean }) { - LoadingRouteHref.setValue(href); - router.replace(href, options); + startTransition(() => { + router.replace(href, options); + }); }, push(href: string, options?: { scroll?: boolean }) { - LoadingRouteHref.setValue(href); - router.push(href, options); + startTransition(() => { + router.push(href, options); + }); }, }; - }, [router]); + }, [router, startTransition]); } -function useRouterLoadingStatus() { - const loadingHref = useSyncExternalStore( - LoadingRouteHref.subscribe, - LoadingRouteHref.getValue, - LoadingRouteHref.getValue, - ); - const pathname = usePathname(); - const searchParams = useSearchParams(); - const searchParamsStr = searchParams?.toString(); - - const routerHref = pathname + (searchParamsStr ? `?${searchParamsStr}` : ""); - const isLoading = loadingHref && loadingHref !== routerHref; +const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - // reset loading on route load +export function DashboardRouterTopProgressBar() { + const [isRouteLoading, startTransition] = useTransition(); // eslint-disable-next-line no-restricted-syntax useEffect(() => { - if (!isLoading) { - LoadingRouteHref.setValue(undefined); - } - }, [isLoading]); - - return isLoading; -} + RouteStartTransitionFn.setValue(startTransition); + }, []); -const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -// Render this on root -function DashboardRouterTopProgressBarInner() { - const isLoading = useRouterLoadingStatus(); const [progress, setProgress] = useState(0); - const progressStartedRef = useRef(false); // eslint-disable-next-line no-restricted-syntax useEffect(() => { - if (!isLoading) { + if (!isRouteLoading) { setProgress(0); progressStartedRef.current = false; return; @@ -85,7 +74,7 @@ function DashboardRouterTopProgressBarInner() { async function updateProgressBar(progress: number, delay: number) { if (!isMounted) { - if (!isLoading) { + if (!isRouteLoading) { setProgress(100); } return; @@ -112,14 +101,14 @@ function DashboardRouterTopProgressBarInner() { return () => { isMounted = false; }; - }, [isLoading]); + }, [isRouteLoading]); - const width = isLoading ? progress : 100; + const width = isRouteLoading ? progress : 100; return ( ); } - -// need to wrap with suspense because of useSearchParams usage -export function DashboardRouterTopProgressBar() { - return ( - - - - ); -}