Created
August 8, 2023 09:35
-
-
Save 7iomka/66243d65bef2c96c8a6cdb09e1959d40 to your computer and use it in GitHub Desktop.
_Next_Router_events
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useUnit } from 'effector-react'; | |
import { useRouter } from 'next/router'; | |
import { useRef } from 'react'; | |
import equal from 'fast-deep-equal'; | |
import { useIsomorphicLayoutEffect } from '@xxx/hooks'; | |
import { $$navigation } from '@/entities/navigation'; | |
import { ContextNormalizers } from '@/shared/lib/next'; | |
import type { PageContext } from '@/shared/lib/nextjs-effector'; | |
import type { AppPropsWithLayout } from '../app.types'; | |
export const withEffectorRouterEvents = (App: any) => { | |
return function AppWithEffectorRouterEvents(props: AppPropsWithLayout) { | |
const router = useRouter(); | |
const beforePopstateChanged = useUnit($$navigation.beforePopstateChanged); | |
const routerInitialized = useUnit($$navigation.routerInitialized); | |
const routerUpdated = useUnit($$navigation.routerUpdated); | |
const routerStateChanged = useUnit($$navigation.routerStateChanged); | |
const isInitRouterEventCalledRef = useRef(false); | |
const normalizedRouterStateRef = useRef<PageContext | null>(null); | |
useIsomorphicLayoutEffect(() => { | |
if (router.isReady && !isInitRouterEventCalledRef.current) { | |
routerInitialized(router); | |
isInitRouterEventCalledRef.current = true; | |
} | |
return () => { | |
isInitRouterEventCalledRef.current = false; | |
}; | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, [router.isReady]); | |
useIsomorphicLayoutEffect(() => { | |
if (router.isReady) { | |
// Update router instance | |
routerUpdated(router); | |
// Update normalized state from router only if it changed | |
const normalizedRouterState = ContextNormalizers.router(router); | |
if (!equal(normalizedRouterState, normalizedRouterStateRef.current)) { | |
routerStateChanged(ContextNormalizers.router(router)); | |
} | |
normalizedRouterStateRef.current = normalizedRouterState; | |
} | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, [router]); | |
// Handle beforePopState | |
// NOTE: currently next support only single callback, that can be overwriten on updates | |
// See: https://github.com/vercel/next.js/discussions/34835 | |
useIsomorphicLayoutEffect(() => { | |
router.beforePopState((state) => { | |
beforePopstateChanged(state); | |
return true; | |
}); | |
}, [router, beforePopstateChanged]); | |
return <App {...props} />; | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment