Firebase Hosting + GatsbyJSでWebサイトを作る 2
ページのレイアウトを作ります。
前回(??)の記事Firebase Hosting + GatsbyJSでWebサイトを作るを一通りやると、
次のようなフォルダ構成になっていると思います (以下の画像にはFirebaseに関するファイルがありませんが)。

フォルダ構成
/srcというフォルダの中にファイルやフォルダを作っていきます。
まずはページのレイアウトをとっても大雑把に決定するファイルを作ります。
/src/components/layout
というフォルダを作り、ここに
layout.js,head.js,header.js,header.module.css,footer.js,footer.module.css
などの何も書いてないファイルを作ります。
・layout.jsはページのレイアウトを大雑把に決めるファイルです。
・head.jsはHTMLファイルのheadタグの部分に書き込む内容を記述するファイルです。
・header.jsはページのヘッダーを記述するファイルです。
・header.module.cssはヘッダーの内容を装飾するCSSファイルです。
・footer.jsはページのフッターを記述するファイルです。
・footer.module.cssはフッターの内容を装飾するCSSファイルです。
すると次のようになるはずです:
/src
|-- pages
| |-- index.js
| |-- 404.js
|-- images
|-- components
|-- layout.js
|-- head.js
|-- header.js
|-- header.module.css
|-- footer.js
|-- footer.module.js
Headの記述
今度はheadの中身を記述します。
その前に、ターミナルで現在のフォルダ(srcの中じゃなくてもokです。firebase.jsonなどが存在しているフォルダの子孫であればどこでも大丈夫)に移動して、
npm install react-helmet
を実行しておきます。
何かがインストールされると思います。
次にhead.jsの中に最低限の記述をします:
import * as React from "react"
import { Helmet } from "react-helmet"
const Head = (props) => (
<Helmet>
<html lang="ja" />
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="description" content={props.description} />
<meta name="author" content={props.author} />
<title>{props.title}</title>
</Helmet>
)
Head.defaultProps = {
title: "不等式botのWebSite",
description: "不等式botのWebSite",
author: "不等式bot"
}
export default Head
ターミナルで何かをインストールしたのは、<Helmet></Helmet>を使いたかったからです。
これはheadタグの中身を記述する際に使うやつです。
たとえばMathJaxを使いたい場合には、この<Helmet></Helmet>で囲まれた中にその旨を記述します。
別の.jsファイルでimport Head from (head.jsの相対パス)と記述することで<Head>という"タグのようなもの"がつかえるようになります。
後で使います。使うときは"<Head title=... author=... description=... />"のようにして使います。
ここで渡された"title"などは"props.title"のようにして参照されます。
また、reactのルールで、javascriptの定数をHTMLの中で使うときには{}で囲まなければいけません。
なので<title>{props.title}</title>のようになっています。
最後に書いている
Head.defaultProps = { ...
は、<Head>に値が渡されなかった場合の初期値の設定です。
とりあえず、あとで使います。
Layoutの記述
layout.jsの中身は以下のようにします (とりあえず、一番シンプルに):
import * as React from "react"
function Layout(props) {
return (
<main>
{props.children}
</main>
);
}
export default Layout
このあと、index.jsなどのファイルの中でLayoutをimportすれば、
<Layout></Layout>で囲まれた中身が{props.children}の部分に挿入される感じになります。
とりあえず使います。
とりあえず、/src/pages/index.jsに移動して、index.jsの中身を次にします:
import * as React from "react"
import Head from "../components/layout/head.js"
import Layout from "../components/layout/layout.js"
const IndexPage = () => {
const description = "最初のページ";
return (
<Layout>
<Head description={description} />
{description}
</Layout>
)
}
export default IndexPage
何をしているかというと、
最初のimportたちで<Head>と<Layout>タグを使えるようにします。
<Layout></Layout>の中に<Head>がありますが、
<Head>の中身は<Helmet>で囲まれているので、
どこに<Head>を記述しても、コンパイル後のHTMLファイルでは<head>の部分に持っていかれます。
しかし、Reactの文法ルールがあり、returnの内容にHTMLを含める場合には
「必ず一つのタグに囲まれたものでなければならない」
というものがあるので、このルールに従って全体を<Layout>で囲んでいます。
定義した定数は{}で囲んで参照されます。
descriptionに「"最初のページ"」が渡されていて、
<Layout>で{description}が囲まれた状態なので、
layout.jsの{props.children}の部分に「"最初のページ"」が渡されます。
つまり、だいたい
<main>最初のページ</main>
と書いているような状態です。
とりあえずbuild
とりあえずターミナルでgatsby buildと打ってビルドします。
(前の記事にもある通りですが、ビルドが終了しない場合はnpm add -D cross-envします)。
ビルドが終了したら、
gatsby serve
と打ちます。
すると
You can now view (サイト名) in the browser.
http://localhost:9000/
と表示されるので、ブラウザでhttp://localhost:9000/と打ってみます。
すると次のような感じになるはずです:

ちゃんと<Head>で設定していないtitleに「"不等式botのWebSite"」が渡されていることが確認できますし、{description}に渡した「"最初のページ"」が表示されています。
page descriptionoに「"最初のページ"」が渡されているか確認するために、コンソールを見てみます。
右上の「更新」の横の3点をクリックして、
その他のツール → デベロッパーツール
と進みます。
すると右側にコンパイル後のHTMLファイルの中身のような何かが表示されると思います。
以下のような感じです:

<head>...</head>の横にある▷を押すと、このタグの中身が表示されます:

ちゃんと
<meta data-react-helmet="true" name="author" content="不等式bot">
<meta data-react-helmet="true" name="description" content="最初のページ">
となっていて、初期値の設定や渡した値が反映されていることが確認できます!
今はページの内容があまりに薄いのでとりあえず適当な感じですが、あとは編集していくだけです。
参考
・React公式「Hello World」
・.defaultPropsについて:PropTypesを用いた型チェック
・コンポーネントと props
Discussion