Reputation: 751
I'm using Next.js 13 with the App Router and have a page that uses dynamic routes. It works well when I run the server locally (localhost:3000//tickets/2
, for instance), but fails with prerender errors when I try to export a static site via npm run build
.
Error occurred prerendering page "/tickets/[id]". Read more: https://nextjs.org/docs/messages/prerender-error
TypeError: Cannot read properties of undefined (reading 'id')
Some notes:
"use client"
at the top of the page. As I understand it, that's required if I'm using the useState
hook."use client"
and all the state management stuff, npm run build
exports everything without a hitch (i.e. Nextjs builds a static page for each ticket id like /tickets/1, tickets/2, etc.).I'm not sure why I'm unable to export a static site with useState
on a page accessed via a dynamic route. Here's my setup, with just the relevant parts:
next.config.js
module.exports = {
output: "export",
images: {
unoptimized: true,
}
};;
app/tickets/[id]/page.js
"use client";
import { useState } from "react";
import Select from "components/Select";
const TICKETS = [
{ id: 0, status: "open" },
{ id: 1, status: "open" },
{ id: 2, status: "resolved" },
{ id: 3, status: "canceled" },
{ id: 4, status: "resolved" }
]
// Dynamic routes; create a page for each ticket ID
export async function generateStaticParams() {
return TICKETS.map((ticket) => ({
id: `${ticket.id}`,
}));
}
export default function Ticket({ params }) {
const { id } = params;
const ticket = TICKETS[id];
const [status, setStatus] = useState(ticket.status);
return (
<div>
<h1>{ticket.id}</h1>
<Select
onValueChange={(e) => {
setStatus(e);
}}
value={status}
/>
</div>
);
}
Upvotes: 9
Views: 8717
Reputation: 432
Try to move client component out of page.js
and import it instead.
generateStaticParams
is not supported in client component, but importing client component in server component is ok.
Ticket.js
"use client"
// ..imports
export default function Ticket({ params }) {
const { id } = params;
const ticket = TICKETS[id];
const [status, setStatus] = useState(ticket.status);
return (
<div>
<h1>{ticket.id}</h1>
<Select
onValueChange={(e) => {
setStatus(e);
}}
value={status}
/>
</div>
);
}
Page.js
import Ticket from "./ticket";
// ...
// Dynamic routes; create a page for each ticket ID
export async function generateStaticParams() {
return TICKETS.map((ticket) => ({
id: `${ticket.id}`,
}));
}
export default function Page({ params }) {
return <Ticket id={params.id}>;
}
Upvotes: 14