Hello,
With Prismic and Next.js 15.x, I keep having this error in any dynamic route:
Error: Route "/[locale]/freelancers/[uid]" used `params.locale`. `params` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
Weirdly, I am already awaiting the params, but still not ok..:
import { SliceZone } from "@prismicio/react";
import type { Metadata } from "next";
import { getLocale } from "next-intl/server";
import { createClient } from "../../../../prismicio";
import { components } from "../../../../slices";
interface Params {
uid: string;
}
export async function generateMetadata({
params: _params,
}: {
params: Promise<Params>;
}): Promise<Metadata> {
const params = await _params;
const locale = await getLocale();
const client = createClient();
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
let page;
try {
page = await client.getByUID("page", params.uid, {
lang: locale,
});
} catch (error) {
console.error(
`Failed to fetch page metadata for UID: ${params.uid}`,
error,
);
}
if (!page) {
return {
title: "Page not found",
description: "The page you are looking for does not exist.",
};
}
return {
title: page.data.meta_title,
description: page.data.meta_description,
alternates: {
canonical: `/${locale === "en" ? "" : `${locale}/`}${params.uid}`,
},
openGraph: {
images: "/og-image.png",
url: `${params.uid}`,
},
};
}
interface Props {
params: Promise<Params>;
}
export default async function PageChild({ params: _params }: Props) {
const params = await _params;
// Validate UID - it should not include file extensions
if (params.uid.match(/\.(png|jpg|jpeg|gif|ico|svg)$/)) {
console.error(`Invalid UID: ${params.uid}`);
return <div>Page not found</div>;
}
const client = createClient();
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
let page;
try {
page = await client.getByUID("page", params.uid, {
lang: "*",
});
} catch (error) {
console.error(
`Failed to fetch page content for UID: ${params.uid}`,
error,
);
}
if (!page) {
return <div>Page not found</div>;
}
return (
<section className="mt-16 sm:mt-32">
<SliceZone slices={page.data.slices} components={components} />
</section>
);
}
Or:
export async function generateMetadata(props: {
params: Params;
searchParams: SearchParams;
}) {
const params = await props.params;
const searchParams = await props.searchParams;
const currentLocale = params.locale;
const client = createClient();
const t = await getTranslations("metas.freelancerPillarPage");
const page = await client.getByUID("child_freelancer", params.uid, {
lang: currentLocale,
});
const keyword = page.data.keyword || undefined;
const currentPage = searchParams.page ? Number(searchParams.page) : 1;
const dynamicTitle = keyword
? t("titleWithKeyword", { keyword: capitalizeWords(keyword) })
: page.data.meta_title || t("defaultTitle");
const dynamicDescription = keyword
? t("descriptionWithKeyword", { keyword: keyword.toLowerCase() })
: page.data.meta_description || t("defaultDescription");
const baseCanonical =
params.locale === "en"
? `/freelancers/${params.uid}`
: `/${params.locale}/freelancers/${params.uid}`;
const canonical =
currentPage > 1
? `${baseCanonical}?page=${currentPage}`
: baseCanonical;
return {
title: dynamicTitle,
description: dynamicDescription,
alternates: {
canonical: canonical,
},
};
}
export default async function FreelancerChildPage(props: {
params: Params;
searchParams: SearchParams;
}) {
const params = await props.params;
const searchParams = await props.searchParams;
const client = createClient();
const session = await getSession();
const isCustomer = session?.user.userType === "CLIENT";
const page = await client.getByUID("child_freelancer", params.uid, {
lang: "*",
});
const keyword = page.data.keyword || undefined;
...
Thanks for the help!