React Routerでページタイトルをloaderのデータにする方法

React Router v7にて、「loaderで取得したデータ」を使って「ページタイトル」を設定する方法を解説します。

設定方法

metaのdataから受け取って、titleに設定します。metaの引数の型はRoute.MetaArgsにすると型情報を持ってこれます。

import type { Route } from "./+types/home";
import type { LoaderFunctionArgs } from "react-router";
export const loader = async ({ params }: LoaderFunctionArgs) => {
// 取得ロジックなど
return { name };
};
export const meta = ({ data }: Route.MetaArgs) => {
return [
{ title: data.name },
{ name: "description", content: `${data.name}ページです。` },
];
};

+types/〇〇 とは?

前述のimportしている./+types/〇〇.react-router/typesディレクトリ内に生成されるファイルです。

たとえばnpx create-react-router@latestのテンプレートの場合、.react-router/typesは次のようになります。

├── +future.ts
├── +routes.ts
├── +server-build.d.ts
└── app
├── +types
│   └── root.ts
└── routes
└── +types
   └── home.ts

この.react-router/typesreact-router devnpm run devなどの実体)で生成されるようです。明示的に作りたいならreact-router typegenを叩きましょう。

公式ドキュメント:Type Safety | React Router

+types/〇〇 はどこに対して相対的?

./+types/〇〇./の部分はどこに対して相対的なんだ」「app/routesには+typesディレクトリなんて無いぞ」と思うかもしれません。

ここでtsconfig.jsonを見てみましょう。

tsconfig.json
{
// ...
"compilerOptions": {
"rootDirs": [
".",
"./.react-router/types"
],
// ...
}
}

rootDirs..react-router/typesの2つが設定されています。これによって、app/routesだけではなく.react-router/types/app/routesからもimport先を探すようになっています。

新しいファイルでRoute型を使いたい場合

新しくルートのファイルを追加するときにRoute型を使いたい場合は次のような流れです。まずはファイルを作ります。

app/routes/piyo/piyo.tsx
// まだRoute型は生成されない

続いてapp/routes.tsに追加します。この時点でreact-router devを実行していれば(すれば)型が生成されます。

app/routes.ts
import { type RouteConfig, index, route } from "@react-router/dev/routes";
export default [
index("routes/home.tsx"),
route("/piyo","routes/piyo/piyo.tsx")
] satisfies RouteConfig;

.react-router/typesは次のようになります。

.react-router/types
├── ...
└── app
├── ...
└── routes
├── +types
│   └── home.ts
└── piyo
└── +types
└── piyo.ts

新しく追加するルートファイルには+types/piyoRoute型が取れます。

app/routes/piyo/piyo.tsx
import type { Route } from "./+types/piyo";

別の方法

meta自体にMetaFunction<typeof loader>という型を付ける方法もあります。

import type { LoaderFunctionArgs, MetaFunction } from "react-router";
export const loader = async ({ params }: LoaderFunctionArgs) => {
// 取得ロジックなど
return { name };
};
export const meta: MetaFunction<typeof loader> = ({ data }) => {
return [
{ title: data.name },
{ name: "description", content: `${data.name}ページです。` },
];
};

ページタイトルにサイト名を入れたい場合

ページ名 | サイト名のようにページタイトルの後ろにサイト名を入れたい場合、自分でformatするユーティリティ関数を作り、こいつを使いまわします。

utils.ts
export const SITE_NAME = "サイト名";
export function formatTitle(pageTitle: string) {
return `${pageTitle} | ${SITE_NAME}`;
}
ページ側
import { formatTitle } from "./utils"
const pageName = "テスト";
export function meta() {
return [
{ title: formatTitle(pageName) },
{ name: "description", content: `${pageName}ページです。` },
];
}

noindexとかもmetaで設定

ついでに。お問い合わせページとかだけnoindexにしたいときもmetaタグなのでmetaに書きます。

const pageName = "お問い合わせ";
export function meta() {
return [
{ title: pageName },
{ name: "description", content: `${pageName}ページです。` },
{ name: "robots", content: "noindex" },
];
}

公式ドキュメント集


以上、React Router v7におけるページタイトルの設定方法でした。