Next.js Discord

Discord Forum

Best way to set titles in app router with lots of pages?

Answered
Sun bear posted this in #help-forum
Open in Discord
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
View full answer

28 Replies

@Sun bear Like `<domain> | <page>` `example.com | login` for example.
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 bear 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 title
@Sun bear is there any better ways?
what's your use case? What do you want to do?
@B33fb0n3 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
@Sun bear 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 bear 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 bear 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 about
@Sun bear 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
Answer
@Sun bear in the same folder?
Indian oil sardine
i'm using something like this

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?
@B33fb0n3 <@1080311571324084275> 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?
@Sun bear 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 possible
@Sun bear 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
@B33fb0n3 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
@Sun bear 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
What you are saying makes no sense:

you saying that you want to fetch it on the client
request to be made in the client
But 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, …
@B33fb0n3 What you are saying makes no sense: you saying that you want to fetch it on the client > request to be made in the client But on the other hand you want to use SSR (**Server**side 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;
@B33fb0n3 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
@Sun bear 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