Short question: how do I get an action to take effect on page-load for the app router equivalent of statically generated pages from static paths in NextJS?
Longer version, my page generation is working fine:
// app/layout.js
import Providers from '@/app/Providers';
export default function RootLayout({ children }) {
return (
<html lang='en'>
<body>
<Providers>
{children}
</Providers>
</body>
</html>
)
}
// app/Providers.js
'use client';
import TrackProvider from '@/utils/trackProvider';
function Providers({children}) {
return (
<TrackProvider>
{children}
</TrackProvider>
)
}
export default Providers;
// app/sample/page.js
import { getLayoutData } from '@/utils/getLayoutData';
async function getPage() {
const allData = await getLayoutData();
const { page } = allData;
return { page };
}
export default async function Page() {
const { page } = await getPage();
return <div>{page}</div>
}
The issue I have is that TrackProvider
provides context for React Tracking. With the old pages router, I would register a page view with a custom hook:
// pages/[slug].js
const Page = (props) => {
usePageTracking(props.page.slug);
return props.actionPage ? <ActionLayout {...props} /> : <Layout {...props} />;
}
where usePageTracking
is a wrapper around useEffect
and useTracking
from React Tracking:
// utils/trackPage.js
'use client';
import { useTracking } from 'react-tracking';
import { useEffect } from 'react';
export function usePageTracking(pageSlug) {
const { trackEvent } = useTracking();
useEffect(() => {
trackEvent({
eventType: 'pageView',
page: pageSlug
});
}, [pageSlug]);
}
But I can't use this same methodology in the new app router, because the page generation is async:
export default async function Page() {
const { page } = await getPage();
usePageTracking(page.slug); // <-- this won't work :(
return <div>{page}</div>
}
What's the right way to accomplish this migration?
You probably need to wrap that functionality in a client component:
export const PageTracking = ({ slug }) => {
usePageTracking(slug)
return null;
}
So your page will end up looking like this:
export default async function Page() {
const { page } = await getPage();
return (
<>
<PageTracking slug={ page.slug } />
<div>{ page }</div>
</>
)
}
There's a similar example / recommendation in Next.js useRouter
migration documentation:
import { Suspense } from 'react'
import { NavigationEvents } from './components/navigation-events'
export default function Layout({ children }) {
return (
<html lang="en">
<body>
{children}
<Suspense fallback={null}>
<NavigationEvents />
</Suspense>
</body>
</html>
)
}