I recently upgraded to Next.js 15, and I'm facing an issue when trying to access params in a dynamic route.
Folder structure:
/app
/product
/[id]
/page.tsx
When I try to access the id from params in my [id]/page.tsx, I get this error:
A param property was accessed directly with
params.id.paramsis now a Promise and should be unwrapped withReact.use()before accessing properties of the underlying params object. In this version of Next.js direct access to param properties is still supported to facilitate migration, but in a future version, you will be required to unwrapparamswithReact.use().
app/product/[id]/page.tsx):
export default async function Page({ params }: { params: { id: string } }) {
const id = params.id; // This throws the error
return <div>Product ID: {id}</div>;
}
I tried changing the function signature to this:
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
return <div>Product ID: {id}</div>;
}
This works, but I'm unsure if it's the correct approach.
I reviewed the Next.js 15 documentation, but there's no clear mention of this behavior change.
Questions:
params in Next.js 15?params now a Promise, and is this an intentional breaking change for future versions?The solution sent by Jasperan may solve the problem, but I hate having to create a "use server" component just to load another "use client" component, when you could just have a single component. I really hate this kind of approach.
The solution for this is actually quite simple: https://github.com/vercel/next.js/issues/71690#issuecomment-2439644682
You can use the react API called "use": https://react.dev/reference/react/use
'use client';
import { use } from 'react';
export default function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = use(params);
return <div>Product ID: {id}</div>;
}
You're correct that you need to use await in Next.js 15 to extract params now (see Next.js docs for an example). This needs to be done in a server component since client components cannot be async.
If you need the params in your client component, you can extract it in a server component first and then pass it down, like so:
import ProductPage from "./productPage";
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
return <ProductPage id={id} />;
}
Then in your client component:
"use client";
export default function ProductPage({ id }: { id: string }) {
return <div>{id}</div>;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With