reactjsnext.jsnext.js13

How can I force a certain page to revalidate from a client component in NextJS?


The problem

I'm making a website with a supabase backend, where people can make things called guides. Each guide has a dedicated dynamic path /guides/[id] and a dedicated edit page /guides/[id]/edit, which contains the form for updating the data in the guide. On submitting the form, I use router.push() from next/navigation to navigate back to /guides/[id] after making the requests to supabase. However, when it navigates back to /guides/[id], it still shows the old cached data - I need to refresh the page to get the updated data.

I don't want to revalidate the page every time it's visited, I only want to revalidate it whenever the form is submitted. Is there a way to do that?

Attempted solutions

I looked at the NextJS docs for revalidatePath. I tried using the function directly in my solution like this:

...
revalidatePath(`/guides/${id}`);
router.push(`/guides/${id}`);
...

But ended up with this error:

Error: Invariant: static generation store missing in revalidateTag _N_T_/guides/18

leading me to believe it could only be called server-side. So, I tried creating an api route /api/revalidate/route.ts like so:

// /api/revalidate/route.ts
import { revalidatePath } from "next/cache";
import { NextRequest } from "next/server";

export async function GET(request: NextRequest) {
  const path = request.nextUrl.searchParams.get("path");

  if (path) {
    revalidatePath(path);
    return Response.json({ revalidated: true, now: Date.now() });
  }

  return Response.json({
    revalidated: false,
    now: Date.now(),
    message: "Missing path to revalidate",
  });
}
// /guide/[id]/edit.tsx
...
await fetch(`/api/revalidate?path=/guides/${id}`);
router.push(`/guides/${id}`);
...

But that didn't work either. What am I doing wrong here?


Solution

  • you are right revalidatePath function can only be called server-side Source.
    So let's explore some options:

    One possible reason for the error is that revalidatePath function is not triggering a re-validation as we expect. The re-validation will happen on the next request to the page after the mark is set Source.

    Another possible reason could be that the revalidatePath function is not able to find the path in the cache. i would ask you to check if the path you're passing to revalidatePath matches the correct path Source.

    Lastly try using router.refresh method to force a refresh of the page after the form submission.Source, Source.

    i wrote an example:

    import { useRouter } from 'next/router';
    
    const MyComponent = () => {
     const router = useRouter();
    
     const handleFormSubmit = async () => {
       // Perform your form submission logic here...
    
       // After the form submission, refresh the page
       router.refresh();
     };
    
     return (
       <form onSubmit={handleFormSubmit}>
         {/* Your form fields here... */}
       </form>
     );
    };
    
    export default MyComponent;
    

    handleFormSubmit is the function that gets called when the form is submitted and then it refresh the page.