Accessing `params` at top-level scope?
Answered
Common paper wasp posted this in #help-forum
Common paper waspOP
I hope I'm using that term right. I'm not a programmer by trade :D. I'm trying to get access to my blog post information defined in my Velite Collection and from reading the docs, the only way I've found is to do it the way I'm doing it now:
I'd like to be able to call my
This is my
import { getPostBySlug } from "@/app/lib/utils";
import { Metadata } from "next";
export const metadata: Metadata = {
}
export default function BlogPost({ params }: { params: { slug: string } }) {
const post = getPostBySlug(params.slug);
return <div dangerouslySetInnerHTML={{ __html: post!.content }}></div>;
}I'd like to be able to call my
getPostBySlug() at the top-level so I can pass what I need (like the title, description and cover) to metadata. Is there a way to do this?This is my
velite.config.jsconst posts = defineCollection({
name: "Post",
pattern: "posts/**/*.md",
schema: s
.object({
title: s.string().max(45),
slug: s.slug("post"),
date: s.isodate(),
updated: s.isodate().optional(),
cover: s.image().optional(),
description: s.string().max(255).optional(),
tags: s.array(s.string()).default([]),
meta: meta,
toc: s.toc(),
metadata: s.metadata(),
excerpt: s.excerpt(),
content: s.markdown(),
})
.transform((data) => ({ ...data, permalink: `/blog/${data.slug}` })),
});Answered by joulev
no,
const getPostBySlug = cache(async (slug) => {
// ...
return {
title: ...,
...
};
});
export async function generateMetadata({ params }) {
const data = await getPostBySlug(params.slug);
return { ... };
}
export default function Page() {
const data = await getPostBySlug(params.slug);
return ...;
}33 Replies
Common paper waspOP
Maybe this is on the right track?
https://nextjs.org/docs/app/building-your-application/optimizing/metadata#dynamic-metadata
https://nextjs.org/docs/app/building-your-application/optimizing/metadata#dynamic-metadata
Trying to follow along, this basic example I tried doesn't seem to work 😦
type Props = {
params: { slug: string };
};
export async function geerateMetadata(
{ params }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
const title = getPostBySlug(params.slug)?.title;
return {
title: title,
};
}Common paper waspOP
Can't figure this out
Common paper waspOP
I saw that this morning but I thought mine was different since I need to use params
Oh I see I think maybe?
Move the const outside the function and pass title to Metadata?
Is there a better way of getting the title of a post?
@Common paper wasp Move the const outside the function and pass title to Metadata?
no,
const getPostBySlug = cache(async (slug) => {
// ...
return {
title: ...,
...
};
});
export async function generateMetadata({ params }) {
const data = await getPostBySlug(params.slug);
return { ... };
}
export default function Page() {
const data = await getPostBySlug(params.slug);
return ...;
}Answer
Common paper waspOP
Oh
😅
Oh neat. So it won't continue to call the function every time the same post is visited?
if your page is static (it most likely is), no
Common paper waspOP
Yeah blog post page is static
This should go in the page or layout or does it not matter?
does the layout have access to the slug?
no it doesn't really matter, as long as it works
@joulev does the layout have access to the slug?
Common paper waspOP
I'm not actually sure if it does or not in next
I'm assuming yes?
Common paper waspOP
Ah okay because they have Params
Okay cool
Common paper waspOP
I think I did something wrong
@joulev I'm sorry, what am I doing wrong here? I shouldn't have marked yet lol
import { getPostBySlug } from "@/app/lib/utils";
import { Metadata, ResolvingMetadata } from "next";
import { title } from "process";
import { cache } from "react";
const getPostBySlug = cache(async (slug: any) => {
const post = await getPostBySlug(slug);
return {
title: post.title,
description: post.description,
};
});
export async function generateMetadata({ params }) {
const data = await getPostBySlug(params.slug);
return {
title: data.title,
};
}
export default function BlogPost({ params }: { params: { slug: string } }) {
const post = await getPostBySlug(params.slug);
return <div dangerouslySetInnerHTML={{ __html: post!.content }}></div>;
}@Common paper wasp I think I did something wrong
what is the error
Common paper waspOP
Oh, it's conflicting with my util
getPostBySlug function with the constant one defined with cacheimport { posts } from "#site/content";
export function getPostBySlug(slug: string) {
return posts.find((post) => post.slug === slug);
}Common paper waspOP
Might have fixed it. Testing then would it be a good developer thing to do to extract this
getPostBySlugInPage function to my utils? And is this the most...programmatic way to do it? Like, this isn't a hack-job is it?import { getPostBySlug } from "@/app/lib/utils";
import { Metadata } from "next";
import { cache } from "react";
type Props = {
params: {
slug: string;
};
};
const getPostBySlugInPage = cache(async (slug: any) => {
const post = await getPostBySlug(slug);
return {
title: post?.title,
description: post?.description,
};
});
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const data = await getPostBySlugInPage(params.slug);
return {
title: data?.title,
};
}
export default function BlogPost({ params }: { params: { slug: string } }) {
const post = getPostBySlug(params.slug);
return <div dangerouslySetInnerHTML={{ __html: post!.content }}></div>;
}Looks like this worked!
Common paper waspOP
I always feel like if I use the TS
? operator on things that may be null, I've done something wrong either in that file or elsewhere to get to this point