How can I clear the cache for GetStaticPaths in NextJs and remove a dynamic route?

This question may seem basic, but I can't seem to find the answer anywhere online.

Currently, I am diving into NextJs (using TypeScript) and I have successfully set up a site with dynamic routes, SSR, and incremental regeneration deployed on Vercel. Below is an example of the code in my dynamic route handler for GetStaticProps and GetStaticPaths:

export const getStaticPaths: GetStaticPaths = async () => {
    const routes = new CmsHelper().GetRoutes();

    const paths = (await routes).items.map((item, index, items) => {
        return item.fields.urlPath;
    })

    return {
        paths: paths,
        fallback: 'blocking',
    };
}

export const getStaticProps: GetStaticProps = async (context) => {
    const urlParts = context.params?.url as string[] || [];
    const urlPath = `/${urlParts.join('/')}`;
    const article = await new CmsHelper().GetArticle(urlPath);
    return {
        props: {
            article
        },
        revalidate: 10,
    }
}

If I request a new path added after build time in the CMS, it regenerates successfully and shows the page.

Everything seems fine so far.

However, if I unpublish a route in the CMS... it still shows up in the app unless I rebuild and redeploy (in development).

So here's my question: how can I dynamically remove a dynamic route from NextJs' GetStaticPaths cache?

I know that GetStaticProps is called at most once every 10 seconds due to the revalidate setting. But as far as I understand, GetStaticPaths is only triggered when a request comes in from a route that is not already cached(?).

In essence, for integration with a headless CMS, how can I handle unpublishing or renaming pages in NextJs without needing a rebuild/deploy?

Thank you in advance!

Answer №1

Perhaps consider trying out this method detailed here.

Additionally, I have included the code here for your reference.

// pages/blog/[slug].js

import {useRouter} from 'next/router'
import DefaultErrorPage from 'next/error'

export async function getStaticProps({ params }) {
  // fetch data from CMS through params
  const post = await getBlogItem(params.slug)
  return {
    props: {
      post
    }
  }
}

export async function getStaticPaths() {
  return {
    fallback: true,
    paths: []
  }
}

export default function MyPage({post}) {
  const router = useRouter()

  if(router.isFallback) {
     return <h1>Loading...</h1>
  }

  // This includes setting the noindex header because static files always return a status 200 but the rendered not found page page should obviously not be indexed
  if(!post) {
    return <>
      <Head>
        <meta name="robots" content="noindex">
      </Head>
      <DefaultErrorPage statusCode={404} />
    </>
  }

  return <h1>{post.title}</h1>
}

Instead of clearing the cache, perhaps handle scenarios where the fetched content is marked as "unpublished," and in that case, display a 404 Not Found page or any other desired outcome.

You can use something like this:

export async function getStaticProps(context) {

    const {params: {id}} = context

    let data;
    try {
        data = await httpClient...
    } catch (err) {
        if (not err is caused due to content being unpublished){
            // re throw it
            throw err;
        }
        // Else handle it gracefully
        data = null;
    }

    return {
        props: {
            data,
        },
        revalidate: 1
    };
}

Then, implement this on your view component:

export default function Data(props) {
    const {data} = props;

    const router = useRouter()

    // If the page is not yet generated, this will be displayed initially until getStaticProps() finishes running
    if (router.isFallback) {
        return <div>Loading...</div>
    }

    if (!data) {
        return (
            <>
                <Head>
                    <meta name="robots" content="noindex"/>
                </Head>
                <DefaultErrorPage statusCode={404}/>
            </>
        )
    }

    return <DataView {...data} />;

}

Answer №2

My issue was somewhat similar, yet slightly different: I encountered difficulties deploying my project's generated URL from the data, particularly when attempting to add new URLs as the data in the database changed.

The solution to my dilemma lay in realizing that I had set the fallback option to false within my getStaticPaths method. Once I switched it to true, the deployment process in production mirrored that of my local development environment.

I noticed that you're providing a string value for your fallback property. Perhaps consider using a boolean value instead, which is outlined in more detail here: https://nextjs.org/docs/basic-features/data-fetching#the-fallback-key-required

Answer №3

Experience the power of On-Demand Incremental Static Regeneration with the latest release of Next.js 12.2 in the summer of 2022. This feature allows you to update generated pages on demand by simply publishing changes in your headless CMS and utilizing its webhook functionalities.

// pages/api/revalidate.js

export default async function handler(req, res) {
  // Verify the secret token for authentication
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Invalid token' })
  }

  try {
    // Provide the actual path that needs revalidation
    // For example, use "/blog/post-1" instead of rewritten paths like "/blog/[slug]"
    await res.revalidate('/path-to-revalidate')
    return res.json({ revalidated: true })
  } catch (err) {
    // In case of an error, Next.js will continue to display the last successfully generated page
    return res.status(500).send('Error revalidating')
  }
}

Explore more about using On-Demand Revalidation here

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

How do I implement data range filtering in Typescript?

Seeking assistance with filtering data by date range and forwarding the results to the client. The objective is to extract tickets created within specific dates, but I keep encountering a console error which is proving challenging to resolve. var befor ...

Encountering a 401 error with NextAuth following the deployment of the website

During the development of my next.js project, I successfully implemented authentication using the next-auth credentials provider. However, upon deploying the website to production, I encountered a 401 error code when attempting to log in. The response me ...

Merge attributes from objects within an array

I am seeking assistance with a basic task in TypeScript as a newcomer to the language. My challenge involves manipulating an array of objects like this: // Sample data let boop = [ {a: 5, b: 10}, {a: 7, c: 8}, {a: 6, b: 7, c: 9} ]; My objectiv ...

Sorting by date and time in a data grid using MUI X is simple with these steps

In the MaterialUI X data grid, I am facing an issue with sorting a column of dates in the format of DD/MM/YYYY HH:mm:ss. Currently, the default sorting only considers the date and does not account for the time which is causing issues with the order. I was ...

Tips for selecting the best className type for material-ui components

Currently, I am integrating material-ui into a react app that is built using typescript. Within the material-ui framework, there is a feature called withStyles which allows styles to be injected into a component through its className. However, I am facing ...

What steps should I take to fix the error "property scrollIntoView of null cannot be read"?

I start a new project using Angular .html file: <a (click)="go()">toto</a> <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam iaculis ex porttitor semper iaculis. Nam dapibus erat interdum, scelerisque magna et, finibus ...

Angular-template static functions refer to functions that do not require an

Our project utilizes the linting-config provided by AirBnB. There is a rule that stipulates class methods must utilize this or be declared as static. While this rule theoretically makes sense, it seems to present challenges within an angular context. Consi ...

@Viewchild doesn't have access to matSort

In my Angular project, I am having trouble getting my @ViewChild instance to work with MatSort in HTML. component.ts file: import { MatSort } from '@angular/material'; export class MyComponent { @ViewChild(MatSort) sort: MatSort; } ngOn ...

Dealing with empty parameters in NextJs and dynamic routes: What's the best approach?

Is there a way to retrieve the URL parameter without using query strings? For example, in the URL http://localhost:3000/test/1, how can we extract the parameter without facing a 404 page when it's omitted? Directory Structure test - [pageNumber].js ...

Is there a way to verify a user's login status?

Currently, I am working on an angular 13 project and incorporating @angular/fire 7 into my development process. I have developed a service with various functions for injection. Below is the code snippet: import { Injectable } from '@angular/core&apos ...

Encountering an error when trying to import a node module in an Angular TypeScript file. The module

Currently, I am in the process of developing an Electron application specifically designed for managing Airplay on MacOS. To accomplish this task, I am utilizing Angular and TypeScript to wrap APIs from a unique npm package known as Airplay npm package. ...

Leveraging NextJS for Advanced Server-Side Rendering with Seamless Integration of React Query in the Front

I have implemented React Query in the following manner: const { data, isSuccess, isLoading } = useQuery(['myQuery', myParams], async () => { return myAjaxCall(myParams); }, { cacheTime: 0 }); The results are then passed into a custom ...

NextJS applications can encounter issues with Jest's inability to parse SVG images

Upon running yarn test, an unexpected token error is encountered: Jest encountered an unexpected token This typically indicates that Jest is unable to parse the file being imported, suggesting it's not standard JavaScript. By default, Jest will use ...

React application experiencing freezing when setInterval function is utilized

I've been working on incorporating Conway's Game of Life into a React project, but I'm encountering freezing issues whenever a new generation is triggered. My assumption is that the problem lies in the excessive overhead from constant DOM re ...

To trigger OnClick events in Next.js SSG, you will need to double click the element for it to run properly

There seems to be an issue where elements with an onClick event listener require a second click to run. It appears that the state is not updating on the initial click, causing this behavior. This problem may be related to using getStaticProps() for SSG on ...

Definitions for images in the following format

I am currently utilizing typescript in conjunction with NextJs and next-images. Here is the code snippet: import css from "./style.sass"; import img from './logo.svg'; import Link from 'next/link'; export default () => <Link hre ...

Describing a function in Typescript that takes an array of functions as input, and outputs an array containing the return types of each function

Can the code snippet below be accurately typed? function determineElementTypes(...array: Array<(() => string) | (() => number) | (() => {prop: string}) | (() => number[])>) { /// .. do something /// .. and then return an array ...

Node C++ Addon Typescript declaration file

I have developed a Node C++ Addon that wraps a class similar to the one outlined in the official Node documentation. By using require(), I am able to access my addon and retrieve the constructor for my class in order to instantiate it. const { MyClass } = ...

Injection of dependencies in Angular can be done outside of the constructor

In my class, I have a constructor that takes in some data. export class MyClass { constructor(data: any) { this.data = data; } } I also want to include ChangeDetectorRef as a parameter in the constructor like this. constructor(data: any, cd: ...

What could be causing input to be blocked in certain situations while using my Angular directive with compile function?

Recently, I created a directive that adds a class based on a certain condition. You can find the code snippet at the end of this question. The directive functions as expected in a simple use case where it's applied to a required field: <input typ ...