Search code examples
reactjsnext.jsssg

How to avoid loading for nonexistent static pages?


I'm making e-commerce Next.js static app.

For my products pages I'm using incremental static generation (I'll call it ISG further) with fallback: true and simple useRouter for showing loading component (like spinner or something else, it doesn’t matter). ISG is very useful function for static sites with frequent updating data (like adding comments, new products and so on), but if I don't have product path (for example /products/nike-pants-12345) the page will return "infinity loading" and error.

The error is below.

Error with non-exist page for ISG

If we take a look in console we can see something like: TypeError: Cannot read property '_id' of null. It means that app didn't find product with requested _id (it could be name, slug and so on).

So, the question is how I can avoid this case and should this one be avoided at all?

export async function getStaticPaths() {
    await dbConnect()

    const products = await ProductModel.find({})

    const paths = products.map((doc) => {
        const product = doc.toObject()
        return {
            params: { id: product._id.toString() }
        }
    })

    /* fallback: true means that the missing pages
    will not 404, and instead can render a fallback */
    return { paths, fallback: true }
}

export async function getStaticProps({ params }) {
    await dbConnect()

    const product = await ProductModel.findById(params.id).lean()
    product._id = product._id.toString()

    // revalidate set the time (in sec) of re-generate page (it imitate SSR)
    return { props: { product }, revalidate: 30 }
}

Solution

  • You could trigger a 404 page by adding a check for product and return notFound: true if no product was found in getStaticProps.

    export async function getStaticProps({ params }) {
        await dbConnect()
    
        const product = await ProductModel.findById(params.id).lean()
    
        if (!product) {
            return {
                notFound: true
            }
        }
    
        product._id = product._id.toString()
    
        // revalidate set the time (in sec) of re-generate page (it imitate SSR)
        return { props: { product }, revalidate: 30 }
    }