Table of contents
If you're wondering why your NextJS 13 app is rendering the default 404 page and not the one you specified in your not-found.js
file - keep reading.
The wrong way
Calling notFound()
outside of your react component (in this case I called it in an async fetch function) will render the default 404 page instead.
// app/restaurant/[slug]/page.js
import { PrismaClient } from '@prisma/client'
import { notFound } from 'next/navigation'
// Instantiate a new Prisma client
const prisma = new PrismaClient()
// Define a function to fetch restaurants by slug using Prisma
export const fetchRestaurantsBySlug = async (slug) => {
// Use Prisma to find a restaurant with the specified slug
const restaurant = await prisma.restaurant.findUnique({
where: {
slug,
}
})
// If the restaurant is not found, call notFound() from Next.js
if (!restaurant) {
notFound()
}
// Otherwise, return the found restaurant
return restaurant
}
// Define a component to render restaurant details based on a slug parameter
export default async function RestaurantDetails({ params }) {
const restaurant = await fetchRestaurantsBySlug(params.slug)
return (
<>
{ // Render the restaurant details UI here... }
</>
)
}
if you navigate to a not found page, you get the default 404 page from NextJS:
but what I wanted to see was my custom 404 page:
which renders from this file:
// app/restaurant/not-found.js
import Image from 'next/image'
import errorMascot from '../../public/icons/error.png'
export default function NotFound() {
return (
<div className='h-screen bg-gray-200 flex flex-col justify-center items-center gap-8'>
<Image src={errorMascot} alt='error' className='w-56' />
<div className='bg-white px-10 py-6 shadow rounded'>
<h3 className='text-xl font-bold'>Well, this is embarrassing.</h3>
<p className='mt-4'>We couldn't find that restaurant.</p>
<p className='mt-4 text-xs'>Error code: 404</p>
</div>
</div>
)
}
The correct way
Turns out, to render your custom Not Found UI from your not-found.js
file, you have to call notFound()
within the react component:
// app/restaurant/[slug]/page.jsx
// ...
// Define a function to fetch restaurants by slug using Prisma
export const fetchRestaurantsBySlug = async (slug) => {
// Use Prisma to find a restaurant with the specified slug
const restaurant = await prisma.restaurant.findUnique({
where: {
slug,
}
})
// If the restaurant is not found, throw an error
if (!restaurant) {
throw new Error('Restaurant not found')
}
// Otherwise, return the found restaurant
return restaurant
}
// Define a component to render restaurant details based on a slug parameter
export default async function RestaurantDetails({ params }) {
let restaurant
try {
// Attempt to fetch the restaurant details based on the provided slug
restaurant = await fetchRestaurantsBySlug(params.slug)
} catch (error) {
// If an error is caught, call the notFound() function provided by Next.js
notFound()
}
return (
<>
{ // Render the restaurant details UI here... }
</>
)
}
Hope this helps!
Resources
https://beta.nextjs.org/docs/api-reference/notfound
https://beta.nextjs.org/docs/api-reference/file-conventions/not-found