🙄

Firebase Hosting + GatsbyJSでWebサイトを作る 2

2022/04/09に公開約4,800字

ページのレイアウトを作ります。
前回(??)の記事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

ログインするとコメントできます