【React】react-helmet-asyncを使ったheadの設定方法 - URLごとに切り替える
今回はreact-helmet-asyncを使ってheadの設定方法について説明します。
前提条件は以下
- VSCode上でcreat react appを使ってReact、TypeScriptの環境で行う
- ESLint(Airbnb)とPrettierを追加して、VSCode上の拡張機能と連動させている
- URLごとにheadの中を変更させる(titleやdescription、canonicalなど)
- OGPの設定はしない
環境は以下です。
- macOS Catalina v10.15.5
- Visual Studio Code v1.57.0
- React v17.0.2
- TypeScript v4.5.5
- react-router-dom v6.2.2
- react-helmet-async v1.2.3
- node.js v16.13.1
react-helmet-asyncを使ってheadの設定する
前提として開発環境は以下の記事に沿って構築しています。この環境に追加してreact-helmet-asyncをインストールする流れになります。
react-helmet-asyncをインストール
react-helmet-asyncと型をインストールします。
npm i --save react-helmet-async @types/react-helmet-async
react-helmet-asyncの詳細については以下をどうぞ。
ディレクトリの構成について
トップページとpage1の2ページがあるイメージです。
この2つの表示を切り替えたときに、headの中を書き換えます。
表示の切り替えはApp.tsx内でreact routerを使って行います。
|_public/
| |- index.html
|
|_src/
|- assets/ (共通で使うCSSや画像をまとめている)
| |- css/
| | |- _base.scss
| | |- _custom-property.scss
| | |- styles.scss
| |
| |- img/
|
|- components/(コンポーネントをまとめている)
| |- blocks/(ページを構成するコンポーネント)
| | |- HeadBlock.tsx
| |
| |- pages/(全ページを管理する)
| | |- home/(トップページ)
| | | |- Home.module.scss
| | | |- Home.tsx
| | |
| | |- page1/(page1ページ)
| | | |- Page1.module.scss
| | | |- Page1.tsx
|
|- App.tsx
|- index.tsx
基本的な書き方
まずはreact-helmet-asyncの基本的な書き方について説明します。
import React from 'react';
import ReactDOM from 'react-dom';
import { Helmet, HelmetProvider } from 'react-helmet-async';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<HelmetProvider>
<Helmet>
<title>サイトのタイトルです</title>
<meta name="description" content="サイトの説明文です" />
</Helmet>
<App />
</HelmetProvider>
</React.StrictMode>,
document.getElementById('root')
);
メインコンポーネント(<App/>の部分)をHelmetProviderで囲み、メインコンポーネントの上にHelmetを配置します。あとはHelmetの中にheadの中に書きたいtileやdescriptionなどの指定します。
react-helmet-asyncによってheadの指定するので、index.html側のheadにはtitleの指定だけにしておきます。
<!DOCTYPE html>
<html lang="ja">
<head>
<title>サイトのタイトルです</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
基本的な使い方はこれだけです。
それではURLごとにheadの表示を切り替える方法について説明します。
URLごとにheadの中を切り替える
App.tsxでreact routerを使ってトップページとpage1ページの表示を切り替えるとします。
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { Home } from './components/pages/home/Home';
import { Page1 } from './components/pages/page1/Page1';
const App = () => (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="page1" element={<Page1 />} />
</Routes>
</BrowserRouter>
);
export default App;
App.tsxを読み込むindex.tsxではHelmetProviderを使ってAppコンポーネントを囲っておきます。
import React from 'react';
import ReactDOM from 'react-dom';
import './assets/css/styles.scss';
import { HelmetProvider } from 'react-helmet-async';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<HelmetProvider>
<App />
</HelmetProvider>
</React.StrictMode>,
document.getElementById('root')
);
head用のコンポーネントを作る
blocksディレクトリにHeadBlock.tsxの名前でhead用のコンポーネントを作成します。例として以下の3つをURLごとに切り替えます。
- title
- description
- canonical
import { VFC } from 'react';
import { Helmet } from 'react-helmet-async';
type Props = {
title?: string;
description?: string;
path?: string;
};
export const HeadBlock: VFC<Props> = (props) => {
const { title, description, path } = props;
return (
<Helmet>
<title>{title ?? 'デフォルトのタイトルです'}</title>
<meta name="description" content={description ?? 'デフォルトの説明文です'} />
<link rel="canonical" href={`https:hoge.com/${path ?? ''}`} />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</Helmet>
);
};
ページごとにheadコンポーネントを読み込む
たとえばトップページでheadコンポーネントを読み込む場合では、Home.tsxに以下のように書きます。
import { HeadBlock } from '@/components/blocks/HeadBlock';
import { Link } from 'react-router-dom';
export const Home = () => (
<>
<HeadBlock />
<div>
<div>トップページです</div>
</div>
</>
);
トップページなのでheadコンポーネントに書いているデフォルト値を適用させるため、titleなどの指定はしていません。
トップページをディベロッパーツールで見てみると、titleなどにheadコンポーネントに指定したものが設定できているのが分かります。
ではpage1ページでheadコンポーネントを設定してみます。
import { HeadBlock } from '@/components/blocks/HeadBlock';
export const Page1 = () => (
<>
<HeadBlock title="page1のタイトルです" description="page1の説明文です" path="page1" />
<div>
<div>page1のページです</div>
</div>
</>
);
HeadBlockコンポーネントにtitleとdescription、pathをpropsとして渡しています。
page1ページをディベロッパーツールで確認すると以下のように反映されているのが分かります。
OGPの設定はできるのか?
ReactではJavaScriptによって動的にHTMLファイルの書き換えが行われます。titleやdescriptionなどはGoogleクロームがJavaScriptも含めて読み込んでくれるので正しく反映してくれますが、FacebookやTwitterで使用するOGP設定についてはうまく機能しません。
OGPの設定をしたい場合はサーバー側と連携するか、ReactのフレームワークであるNext.jsやGatsby.jsを使うことになります。
トップページのみOGPを適用させたいのであればreact-helmet-asyncは使わず、index.htmlのheadに直接設定しましょう。
おわりに
今回はreact-helmet-asyncを使ってheadの設定方法について説明しました。URLごとにheadの中を書き換えることはできましたが、OGPについては機能しないことを覚えておきましょう。