diff options
| author | Armand Philippot <git@armandphilippot.com> | 2023-11-15 17:09:13 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2023-11-15 17:26:17 +0100 |
| commit | 36baf3e5725aeae00d81d3a082b3c04074e09f8e (patch) | |
| tree | 34069dc40f7cd45707e8cea0a8993e94841af778 /src/utils | |
| parent | c826ad66df066b90b09009f2f4b83b56d018436e (diff) | |
refactor(hooks): replace useRouteChange with useOnRouteChange hook
* handle both event start and event complete
* clean the effect
* add tests
Diffstat (limited to 'src/utils')
| -rw-r--r-- | src/utils/hooks/index.ts | 2 | ||||
| -rw-r--r-- | src/utils/hooks/use-on-route-change/index.ts | 1 | ||||
| -rw-r--r-- | src/utils/hooks/use-on-route-change/use-on-route-change.test.tsx | 69 | ||||
| -rw-r--r-- | src/utils/hooks/use-on-route-change/use-on-route-change.ts | 35 | ||||
| -rw-r--r-- | src/utils/hooks/use-route-change.tsx | 10 |
5 files changed, 106 insertions, 11 deletions
diff --git a/src/utils/hooks/index.ts b/src/utils/hooks/index.ts index ad412c8..d42c32b 100644 --- a/src/utils/hooks/index.ts +++ b/src/utils/hooks/index.ts @@ -13,6 +13,7 @@ export * from './use-local-storage'; export * from './use-match-media'; export * from './use-mutation-observer'; export * from './use-on-click-outside'; +export * from './use-on-route-change'; export * from './use-pagination'; export * from './use-posts-list'; export * from './use-prism'; @@ -20,7 +21,6 @@ export * from './use-prism-theme'; export * from './use-reading-time'; export * from './use-redirection'; export * from './use-reduced-motion'; -export * from './use-route-change'; export * from './use-scroll-lock'; export * from './use-scroll-position'; export * from './use-scrollbar-width'; diff --git a/src/utils/hooks/use-on-route-change/index.ts b/src/utils/hooks/use-on-route-change/index.ts new file mode 100644 index 0000000..d7f54c8 --- /dev/null +++ b/src/utils/hooks/use-on-route-change/index.ts @@ -0,0 +1 @@ +export * from './use-on-route-change'; diff --git a/src/utils/hooks/use-on-route-change/use-on-route-change.test.tsx b/src/utils/hooks/use-on-route-change/use-on-route-change.test.tsx new file mode 100644 index 0000000..afcad0a --- /dev/null +++ b/src/utils/hooks/use-on-route-change/use-on-route-change.test.tsx @@ -0,0 +1,69 @@ +import { describe, it } from '@jest/globals'; +import { render, screen as rtlScreen } from '@testing-library/react'; +import { userEvent } from '@testing-library/user-event'; +import Link from 'next/link'; +import nextRouterMock from 'next-router-mock'; +import { MemoryRouterProvider } from 'next-router-mock/MemoryRouterProvider'; +import { + type OnRouteChangeHandler, + useOnRouteChange, + type OnRouteChangeStep, +} from './use-on-route-change'; + +type TestComponentProps = { + callback: OnRouteChangeHandler; + href: string; + step?: OnRouteChangeStep; +}; + +const TestComponent = ({ callback, href, step }: TestComponentProps) => { + useOnRouteChange(callback, step); + + return ( + <MemoryRouterProvider> + <Link href={href}>New page</Link> + </MemoryRouterProvider> + ); +}; + +describe('useOnRouteChange', () => { + it('trigger a callback when the route change event starts', async () => { + const cb = jest.fn(); + const user = userEvent.setup(); + const newPage = '/new-page'; + + nextRouterMock.push('/initial-page'); + + render(<TestComponent callback={cb} href={newPage} />); + + expect(cb).not.toHaveBeenCalled(); + + await user.click(rtlScreen.getByRole('link')); + + expect(nextRouterMock).toMatchObject({ + asPath: newPage, + pathname: newPage, + }); + expect(cb).toHaveBeenCalled(); + }); + + it('can trigger a callback when the route change event is complete', async () => { + const cb = jest.fn(); + const user = userEvent.setup(); + const newPage = '/new-page'; + + nextRouterMock.push('/initial-page'); + + render(<TestComponent callback={cb} href={newPage} step="end" />); + + expect(cb).not.toHaveBeenCalled(); + + await user.click(rtlScreen.getByRole('link')); + + expect(nextRouterMock).toMatchObject({ + asPath: newPage, + pathname: newPage, + }); + expect(cb).toHaveBeenCalled(); + }); +}); diff --git a/src/utils/hooks/use-on-route-change/use-on-route-change.ts b/src/utils/hooks/use-on-route-change/use-on-route-change.ts new file mode 100644 index 0000000..85e7060 --- /dev/null +++ b/src/utils/hooks/use-on-route-change/use-on-route-change.ts @@ -0,0 +1,35 @@ +import { useRouter } from 'next/router'; +import { useEffect } from 'react'; + +export type OnRouteChangeStep = 'start' | 'end'; + +export type OnRouteChangeHandler = () => void; + +/** + * React hook to trigger a callback function on route change. + * + * @param {OnRouteChangeHandler} handler - The callback to trigger. + * @param {OnRouteChangeStep} [step] - The event step. + */ +export const useOnRouteChange = ( + handler: OnRouteChangeHandler, + step: OnRouteChangeStep = 'start' +) => { + const router = useRouter(); + + useEffect(() => { + if (step === 'end') { + router.events.on('routeChangeComplete', handler); + + return () => { + router.events.off('routeChangeComplete', handler); + }; + } + + router.events.on('routeChangeStart', handler); + + return () => { + router.events.off('routeChangeStart', handler); + }; + }, [handler, router.events, step]); +}; diff --git a/src/utils/hooks/use-route-change.tsx b/src/utils/hooks/use-route-change.tsx deleted file mode 100644 index 2eff6e9..0000000 --- a/src/utils/hooks/use-route-change.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { useRouter } from 'next/router'; -import { useEffect } from 'react'; - -export const useRouteChange = (callback: () => void) => { - const { events } = useRouter(); - - useEffect(() => { - events.on('routeChangeStart', callback); - }, [events, callback]); -}; |
