0

On this page, I need to cache my API function because I need the same data in both the Page, as well as in the generateMetadata function.

Since I'm using Axios, and not fetch, the deduplication doesn't happen automatically and I have to wrap my API call into React's cache function instead.

Problem is, if I navigate to another page and back to this one, I'm receiving the same old state data. What I want instead is the same behavior of getServerSideProps where we always load fresh data from the server.

import * as UsersApi from "@/network/api/users";
import { notFound } from "next/navigation";
import { NotFoundError } from "@/network/http-errors";
import UserProfilePage from "./UserProfilePage";
import { Metadata } from "next";
import { cache } from "react";

interface PageProps {
    params: { username: string; }
};

// TODO: How can I dedupe requests without getting stale data on page navigation?
const getUser = cache(UsersApi.getUserByUsername);

export async function generateMetadata({ params: { username } }: PageProps): Promise<Metadata> {
    try {
        const user = await getUser(username);
        return {
            title: `${user.username} - Flow Blog`,
        };
    } catch (error) {
        if (error instanceof NotFoundError) {
            notFound();
        } else {
            throw error;
        }
    }
}

export default async function Page({ params: { username } }: PageProps) {
    const user = await getUser(username);
    return <UserProfilePage user={user} />;
}
Fabio Nettis
  • 1,150
  • 6
  • 18
Florian Walther
  • 6,237
  • 5
  • 46
  • 104

1 Answers1

1

You can export the segment configuration dynamic inside your page component and set it to force-dynamic. Segment-level caching allows you to cache and revalidate data used in route segments. This will run the method each time the page is requested, replicating the behavior seen inside the pages directory using getServerSideProps.

import { cache } from 'react';

const getMyData = cache(async () => {
  // fetch your data ..
});

async function MyPage(): Promise<JSX.Element> {
  const response = await getMyData();
  return <></>;
}

export const dynamic = 'force-dynamic';

By then wrapping your function inside the react's cache function the request will automatically be de-duplicated by react.

You can find more information about the caching behavior of requests inside the official documentation.

Fabio Nettis
  • 1,150
  • 6
  • 18
  • Nope, `force-dynamic` is still returning the same stale data (unless you refresh the page). – Florian Walther May 15 '23 at 15:09
  • So it is returning the same data on client side navigation? Are you navigating with `next/link`? – Fabio Nettis May 15 '23 at 16:59
  • yes to both questions – Florian Walther May 16 '23 at 13:01
  • That is strange working on a Next.js 13.4.1 instance at the moment and path segment configuration + cache property on the fetch request itself does it for me. Have you tried using fetch instead of axios and seeing if that fixes it. – Fabio Nettis May 16 '23 at 13:10
  • What did you change in the fetch configuration? Because if you disabled caching, then it's not surprising. – Florian Walther May 16 '23 at 13:26
  • Wait, it seems that your original suggestion of `force-dynamic` actually works. I must've been testing the wrong page earlier. – Florian Walther May 16 '23 at 13:29
  • No problem, great that I was able to help you. I'd strongly recommend checking out the new documentation anyway, a lot has changed in Next.js 13. – Fabio Nettis May 16 '23 at 13:48
  • Yea, I'm actually reading the documentation while figuring this out. But a lot of is not properly described yet. My page should already be dynamic, apparent from the fact that it fetches new data after a page refresh. It's not clear to me why force-dynamic is necessary additionally. – Florian Walther May 16 '23 at 14:31
  • The fact that I have a dynamic URL param but no `generateStaticParams` already makes it dynamic as far as I understand. – Florian Walther May 16 '23 at 14:32
  • Turns out, I accepted the answer too early. It does not work after building the project. – Florian Walther May 18 '23 at 08:57