Next.jsのApp Routerで404ページのtitleを設定する
Next.jsのApp Routerで404ページのtitleを設定する方法がすこしややこしいので解説します。
普通のページでtitleを設定
404ページでのtitle設定の前に通常のページでtitle設定を行う方法を解説します。
page.tsx
内で静的なtitleならmetadata
オブジェクト、動的なtitleならgenerateMetadata
関数をexportすることで設定ができます。
metadata
オブジェクトではtitleプロパティにtitleを指定してexportします。
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'サイトのタイトル'
}
generateMetadata
関数では関数内で動的にtitleを生成するコードを記述して生成したtitleをプロパティにを指定してexportします。
import type { Metadata } from 'next'
export function generateMetadata(): Metadata {
// タイトルを動的に取得するコード
const { title } = getPageTitle()
return {
title
}
}
title templateの利用
よく利用する「ページタイトル | サイト名」などの指定はtitle templateを利用すると簡単に設定可能です。
layout.tsx
などで以下のようにtemplate
プロパティを指定しておくと下層のpage.tsx
で指定されたtitleにテンプレートを適用して反映してくれます。
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: {
template: '%s | サイト名',
default: 'サイト名'
}
}
同階層のpage.tsx
やmetadata
の指定がない下層のpage.tsx
ではdefault
プロパティの指定が採用されます。
404ページでtitleを設定
Next.jsのApp Routerではnot-found.tsx
というファイルを作成することで404ページに適用することができます。
以下のようにmetadata
オブジェクトをexportしておくことでtitleには「404 | サイト名」という値が反映されます。
import type { Metadata } from 'next'
export const metadata:Metadata = {
title: '404'
}
export default function Page() {
return (
<div>
<h1>404ページ</h1>
</div>
);
}
動的ルーティングでtitleを設定
動的ルーティングでtitleを設定する場合でも普通のページでのtitle設定と変わりません。
動的ルーティングの場合は動的にtitleをつけることが多いのでgenerateMetadata
関数を使うことが多いでしょう。
以下のように http://localhost:3000/xxx
でページが表示でき、xxxの部分をtitleに含めようとすると以下のような指定になります。
import type { Metadata } from 'next'
type Props = {
params: {
slug: string
}
}
export function generateMetadata({ params }:Props): Metadata {
return {
title:`${params.slug}のページ`
}
}
export default function Page({ params }:Props) {
return (
<h1>{params.slug}のページ</h1>
);
}
この場合、http://localhost:3000/aa
にアクセスした場合のtitleは「aaのページ | サイト名」に、http://localhost:3000/bb
にアクセスした場合のtitleは「bbのページ | サイト名」になります。
動的ルーティングで404ページにする
動的ルーティングで404ページを指定するにはnotFound
関数を利用します。
今回はhttp://localhost:3000/aa
とhttp://localhost:3000/bb
しか許可せずにそれ以外を404にするとしましょう。
その場合以下のようにslugがaaとbb以外の場合にはnotFound
関数を実行します。
+ import { notFound } from 'next/navigation'
import type { Metadata } from 'next'
type Props = {
params: {
slug: string
}
}
export function generateMetadata({ params }:Props): Metadata {
return {
title:`${params.slug}のページ`
}
}
export default function Page({ params }:Props) {
+ if(!['aa','bb'].includes(params.slug)){
+ notFound()
+ }
return (
<h1>{params.slug}のページ</h1>
);
}
これで、http://localhost:3000/cc
にアクセスした場合404ページが表示できるのが確認できるのですがtitleが「ccのページ | サイト名」になっており、app/not-found.tsx
で指定したtitleの指定は反映されていません。
動的ルーティングで404ページでのtitle指定
app/not-found.tsx
で指定したtitleの指定を反映したい場合はgenerateMetadata
関数内でもnotFound
関数を実行する必要があります。
import { notFound } from 'next/navigation'
import type { Metadata } from 'next'
type Props = {
params: {
slug: string
}
}
export function generateMetadata({ params }:Props): Metadata {
+ if(!['aa','bb'].includes(params.slug)){
+ notFound()
+ }
return {
title:`${params.slug}のページ`
}
}
export default function Page({ params }:Props) {
if(!['aa','bb'].includes(params.slug)){
notFound()
}
return (
<h1>{params.slug}のページ</h1>
);
}
これでは複雑な条件の場合に、ページコンポーネント関数内
でもgenerateMetadata
関数内でも重複するエラーハンドリングが発生してちょっと面倒です。
app/not-found.tsxで共通のtitleを設定
上記のように全ページのgenerateMetadata
関数内でもエラーハンドリングを行うのは現実的ではありません。
これは、app/not-found.tsx
を以下のように変更することで全ページで共通のtitleを設定することが可能になります。
-import type { Metadata } from 'next'
-
-export const metadata:Metadata = {
- title: '404'
-}
-
export default function Page() {
return (
<div>
+ <title>404 | サイト名</title>
<h1>404ページ</h1>
</div>
);
}
JSX内にtitle要素を指定することでページタイトルに反映されるようになります。
ただ、title templateの指定は有効にならないのでtemplateの内容を継承する形で指定する必要があります。
ページ事にnotFoundを指定するよりかは格段と楽になるので試してみてください。
Discussion