leveraging hooks in NextJS app router for static page generation

How can I make an action take effect on page-load for the app router equivalent of statically generated pages from static paths in NextJS?

Everything is working fine with my page generation:

// 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 lies with the TrackProvider that provides context for React Tracking. In the old pages router, I would register a page view using a custom hook:

// pages/[slug].js
const Page = (props) => {
  usePageTracking(props.page.slug);

  return props.actionPage ? <ActionLayout {...props} /> : <Layout {...props} />;
}

where usePageTracking wraps 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]);
}

However, this methodology cannot be used in the new app router due to the async nature of page generation:

export default async function Page() {
    const { page } = await getPage();
    usePageTracking(page.slug); // <-- this won't work :(

    return <div>{page}</div>
}

What is the correct approach to handle this migration?

Answer №1

It appears that implementing the desired functionality requires encapsulating it within a client component:

export const PageTracker = ({ id }) => {
  usePageTracker(id)

  return null;
} 

To incorporate this, modify your page structure as follows:

export default async function HomePage() {
  const { data } = await fetchData();

  return (
    <>
      <PageTracker id={ data.id } />

      <div>{ data.content }</div>
    </>
  )
}

A similar example and recommendation is available in the Next.js documentation for migrating to useRouter:

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>
  )
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to upload a local image using JavaScript for TensorFlow?

I am having trouble loading a data.jpg file to be used by tensorflow mobilenet. When I try to require the file normally, I encounter an error message: So, my question is how can I load an image in my JavaScript code for use? I have tried various methods of ...

Issue with OnClientClick functionality not functioning as expected

I am having trouble with the validation function that is supposed to be triggered when clicking on the back and next buttons in my code. For some reason, the OnClientClick validation function is not being called when I click on the buttons. Can anyone pro ...

JavaScript form validation: returning focus to textfields

I am currently working on a project where I am using JQuery and JavaScript to create an input form for time values. However, I am facing challenges in getting the JavaScript code to react correctly when incorrect input formats are detected. I have a group ...

Error encountered: 'applePaySession.completeMerchantValidation' is not a valid object reference when attempting to process a successful apple pay payment

So, I'm having an issue with the user's payment going through but encountering undefined value when checking compatibility. I've been trying to debug this problem in my code snippet below: setCanDisplayApplePay() { var client = n ...

Durable Container for input and select fields

I need a solution for creating persistent placeholders in input and select boxes. For instance, <input type="text" placeholder="Enter First Name:" /> When the user focuses on the input box and enters their name, let's say "John", I want the pl ...

"Exploring the benefits of using nested mapping for res.json() in an Express application

I have been developing an express application (server-side) that offers movie information to users, and I am attempting to send a JSON response in the following format: { "title": "Star Trek: First Contact", "year": 1996, ...

Dynamic and static slugs in Next.js routing: how to navigate efficiently

I am facing a scenario where the URL contains a dynamic slug at its base to fetch data. However, I now require a static slug after the dynamic one to indicate a different page while still being able to access the base dynamic slug for information. For Ins ...

how can I use jQuery to disable clickable behavior in HTML anchor tags?

Here is the HTML code I am working with: (note -: I included j library on the top of page ) <div class="WIWC_T1"> <a href="javascript:void(0);" onClick="call_levelofcourse();popup('popUpDiv1')">Level of Course</a> </di ...

Injecting resolve values from UI router into Angular Jasmine tests

I am facing an issue in my Angular application where UI router resolves a promise into the controller. However, when attempting to test this controller using Karma, I receive an error about an unknown provider. How can I inject a mock object into the test ...

How can I stretch a background image using jquery to cover the entire document instead of just the window

I have implemented a plugin called https://github.com/srobbin/jquery-backstretch to effectively stretch the background image. The problem arises when the content of the page is long enough to create a scrollbar. In this case, while scrolling, the backgrou ...

The date format is malfunctioning -> Error: The date provided is not valid

My goal is to convert the date format from 2022-01-17T21:36:04.000Z to January 18th using the npm package, dateFormat. I found success with the following code snippet: const date = dateFormat("2022-01-17T21:36:04.000Z", "mmmm dS"); However, when trying t ...

Guide on efficiently inserting values into an array of objects

I'm looking to extract specific values from the enum below enum p { XDR = 1, PT1M = 2, PT1M_ = 2, PT5M = 3, PT5M_ = 3, PT15M = 4, PT15M_ = 4, PT1H = 5, PT1H_ = 5, P1D = 6, P1D_ = 6, P7D = 7, P1W = 7, ...

Sorry, we couldn't locate the API route you are looking for

Within my Next.js project resides the file main/app/api/worker-callback/route.ts: import { NextApiResponse } from "next"; import { NextResponse } from "next/server"; type ResponseData = { error?: string }; export async function PO ...

Is there a way to retrieve random data based on either product id or slug within a single component using useQuery? Currently, all components are displaying the same data

Here is the code I wrote: const fetchCartItem = async () => { if (token) {const {data } = await axios.get(API.GET_PRODUCT_DETAILS_BY_PRODUCT_ID.replace("[ProductID]",item?.ProductID),{headers:{Authorization: token,},});setCartLoading(fal ...

Display Image After Uploading with AJAX

After spending nearly 3 hours working on implementing file uploads via AJAX, I have finally managed to get it up and running smoothly. Take a look at the code below: View <div class="form-horizontal"> <div class="form-group"> @Htm ...

Tips for passing a page as an argument in the function parameter of the page.evaluate() method?

I keep running into this issue when I pass the page as an argument: TypeError: Converting circular structure to JSON --> commencing at object with constructor 'BrowserContext' | property '_browser' -> object with const ...

How can I remove a row from an MVC webgrid using an ajax call?

Within my MVC Razor view, I have a partial view containing webgrid data. My goal is to include an action link to delete a specific row of data. To accomplish this, I crafted the following JavaScript function: function delMeal(pid) { if (confirm("Do yo ...

Node.js scheduler library for triggering events based on time in a cron-like fashion

Currently, I am utilizing Node.js to develop a web application. My aim is to trigger events at specific times. While I am aware of using setTimeout and computing the time difference from the present moment, this method does not account for various timezone ...

Revising HTML content when Angular array is modified

I have a code snippet below where I am updating the value of an object in the first item of an array. However, I'm struggling to find a way to "refresh" the HTML view so that the changes are immediately reflected on the browser. var dataArr ...

Performing two API calls using Jquery to fetch distinct dynamic elements within two nested $.each loops

There's an API link that contains crucial data about phone brands. From this initial data, I have to create a second API call for each brand to gather more detailed information. For example, the first JSON file (urlphonebrands) lists 3 phone brands - ...