Best way to set titles in app router with lots of pages?
Answered
Sun bear posted this in #help-forum
Sun bearOP
Like
<domain> | <page>
example.com | login
for example.Answered by B33fb0n3
that depends on how you structure your project. Some examples on how you can structure your project are here: https://nextjs.org/docs/app/building-your-application/routing/colocation#project-organization-strategies
I guess minimum one of the suites your case
I guess minimum one of the suites your case
28 Replies
you can use a template inside your title or description or ... to put everything together. Example:
export const metadata: Metadata = {
title: {
default: "I am some title", // this will be used as title on the page where you add this metadata
template: "%s | Example.com", // the %s will be exchanged with the new title, when you set a new title someone on any child
},
}
Sun bearOP
How would I do it from the page file where its marked as 'use client'?
you can only set the metadata inside server component. However you can do a little trick and set the
document.title
to your desired titleSun bearOP
is there any better ways?
what's your use case? What do you want to do?
Sun bearOP
Literally just add custom titles to indicate what page the user is one, but alot of my pages are marked as 'use client' due to the states and everything involved
the page.tsx itself is by default always a server component in app router. So keep this serverside especially for that kind of stuff and only import your client components into it. Like that most of your page will be rendered serverside and only the parts that need to be client components are client components
Sun bearOP
what file structure should I use for this then?
you would use a page.tsx as server component and inside this you would import your client components. It could look like this:
// page.tsx
// add some metadata
export default function Page() {
// serverside
const post = await getLastBlockPost()
return <>
<h1>My Blog Page</h1>
<BlogPost post={post}/> // serverside
<CommentSection initialComments={post.comments} postId={post.id}/> // clientside
</>
}
Sun bearOP
I understand that part, I'm asking how I would structure the actual files in my project directory
create a
page.tsx
and create a YourClientComponent.tsx
as your client component file. Nothing more is needed for what I am talking aboutSun bearOP
in the same folder?
that depends on how you structure your project. Some examples on how you can structure your project are here: https://nextjs.org/docs/app/building-your-application/routing/colocation#project-organization-strategies
I guess minimum one of the suites your case
I guess minimum one of the suites your case
Answer
Indian oil sardine
i'm using something like this
page.tsx is the server component where i set metadata
page.client.tsx is the client component
app/
├── (routes)
│ └── example-page/
│ ├── page.tsx
│ └── page.client.tsx
page.tsx is the server component where i set metadata
import type { Metadata } from "next";
import { getUser } from "@/_data/user";
import { getEmployeeDirectory } from "./_lib/employee-directory.queries";
import {
dehydrate,
HydrationBoundary,
QueryClient,
} from "@tanstack/react-query";
import EmployeeDirectoryClient from "./page.client";
export const metadata: Metadata = {
title: "Employee Directory | Your Site",
};
export default async function EmployeeDirectoryPage() {
const user = await getUser();
const queryClient = new QueryClient();
await queryClient.prefetchQuery({
queryKey: ["employees"],
queryFn: () => getEmployeeDirectory(),
});
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<EmployeeDirectoryClient user={user} />
</HydrationBoundary>
);
}
page.client.tsx is the client component
"use client";
import { Suspense } from "react";
import { Heading } from "@/components/catalyst/heading";
import { DataTable } from "@/components/data-table/data-table";
import { columns } from "./columns";
import { useQuery } from "@tanstack/react-query";
import { getEmployeeDirectory } from "./_lib/employee-directory.queries";
import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton";
import { UpdateEmployeeDirectory } from "./_components/update-employee-directory";
export default function EmployeeDirectoryClient({ user }: { user: User }) {
const { data: employees } = useQuery({
queryKey: ["employees"],
queryFn: () => getEmployeeDirectory(),
});
return (
<div>
<div>
<Heading>Employee Directory</Heading>
</div>
<Suspense fallback={<DataTableSkeleton />}>
<DataTable
data={employees}
columns={columns}
/>
</Suspense>
</div>
);
}
@Sun bear solved?
Sun bearOP
Not yet, my data is fetched from a seperate Express backend and I'm unsure how I would do it with that?
you can either fetch it inside your page.tsx and set it thought the
generateMetadata
function or fetch your express app clientside and set it via document.title
both ways are technically possibleSun bearOP
Does
generateMetadata
work in a client component?no, it's also only for server components. You can also do a combination: fetch your epxress server, serverside and pass it down via props and set the title to the value from the props
Sun bearOP
Okay, say I want to fetch data in one page, and reuse that response across all my other components, and I need the request to be made in the client, how would I go about doing this when switching to SSR
If that makes sense
What you are saying makes no sense:
you saying that you want to fetch it on the client
The best flow would be to fetch everything serverside and pass the data to your components that needs them. Like that you can use SSR and also get rid of all the other problems of setting metadata, titles, …
you saying that you want to fetch it on the client
request to be made in the clientBut on the other hand you want to use SSR (Serverside rendered)
switching to SSR
The best flow would be to fetch everything serverside and pass the data to your components that needs them. Like that you can use SSR and also get rid of all the other problems of setting metadata, titles, …
Sun bearOP
Nevermind on that, got it mostly sorted out. One question though, I've noticed that when switching to private folders (like done in the images you sent above) for better organisation, I get the following error when trying to render any icons, I'll attach the error & next config below
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ['@svgr/webpack'],
});
return config;
},
};
export default nextConfig;
Which message solved the initial question of this thread?
Sun bearOP
Sorting using private folders basically
But also raised new issues I need help fixing
your new topic looks like a whole different topic. Please create another thread to be able to find solutions. If I marked the wrong message as solution, feel free to mark another one
Sun bearOP
Done, #Webpack SVGR not working in certain directories