GatsbyでHello, worldからサイトを作ってみる(2) レイアウトの作成

2019.5.25 12:00

概要

サイトのページにおいては、例えば「見た目の統一感を出すために各ページで同じレイアウトにする」といったように、どのページでも同じ部分、つまり共通部分というものが出てくる。
なにも考えずにページをコピペし続けていると、共通部分がいろいろなページに書かれてしまい、いざレイアウトの変更をしようとしても気軽にできなくなってしまう。

そこで、今回は共通部分とページごとに異なる部分を分離して記載する方法を紹介したい。

画面のレイアウト検討

ポートフォリオということで、ざっくり下記の図のようなレイアウトで作ってみることにする。

2-1

左側にMenuを置いて右側にページごとに異なるコンテンツを置くというところがこのサイトのページ共通のレイアウトとなる。ゆえに、Menuも2つのページで共通の部分となる。

この場合、用意するファイルは下記の通りとなる。

  • src/ -- すでにあるフォルダ

    • pages/ -- すでにあるフォルダ

      • index.js -- すでにあるファイル
      • detail.js -- hogehoge.jsのファイル名を変更する
    • components/ -- 新規作成フォルダ

      • layout.js -- 新規作成ファイル
      • menu.js -- 新規作成ファイル
      • item-list.js -- 新規作成ファイル
      • item.js -- 新規作成ファイル
      • detail.js -- 新規作成ファイル

componentsはページの一部となる部品(コンポーネント)を実装したものを置く場所である。

layout.js

一見して図からは分からないが、共通のレイアウトを記載する場所としてlayout.jsというファイルを用意しておくことが重要なポイントである。詳しくは次項で紹介する。なお、ファイル名は必ずしもlayout.jsである必要はないことに留意する。

ページの実装

まずはページを実装する。ざっくりと枠組だけで考えると、こんな感じのHTMLにすればよいだろう。

src/pages/index.js

<body>
  <div>Menu</div>
  <div>
    ItemList
    <div>Item</div>
    <div>Item</div>
  </div>
</body>

src/pages/detail.js

<body>
  <div>Menu</div>
  <div>
    Detail
  </div>
</body>

2つのページを見比べると、共通部分は下記の部分になることがわかるので、これをlayout.jsとしてコンポーネントにする。

<body>
  <div>Menu</div>
  <div>
    <!-- ここにページごとに違うものが入る -->
  </div>
</body>

図にすると、

2-2

というイメージである。

以上を踏まえてページと共通レイアウトのコンポーネントを実装したのが下記である。

src/pages/detail.js

import React from "react"
import Layout from "../components/layout"
import Detail from "../components/detail"

export default () => (
  <Layout>
    <Detail />
  </Layout>
)

src/pages/index.js

import React from "react"
import Layout from "../components/layout"
import ItemList from "../components/item-list"

export default () => (
  <Layout>
    <ItemList />
  </Layout>
)

src/component/layout.js

import React from "react"

import Menu from "./menu"

import styles from "./layout.module.css"

export default ({ children /* childrenでLayoutタグで囲まれた内容を取得できる */ }) => (
  <div className={styles.container}>
    <div className={styles.menu}>
      <h3>Menu</h3>
      <Menu/>
    </div>
    <div className={styles.content}>
      {children}
    </div>
  </div>
)

レイアウトに関する情報はすべて<Layout>のコンポーネントの中に実装されているので、ページからはレイアウトに関する具体的な記載はなく、スッキリしている。

その他のコンポーネントの実装

残りのコンポーネントも実装していく。あわせて、CSSも記載する。

src/component/detail.js

import React from "react"

export default () => (
  <div>
    Detail
  </div>
)

src/component/item.js

import React from "react"
import {Link} from "@reach/router";

export default ({ id, title, description }) => (
  <Link to={`/detail?id=${id}`}>
    <div>
      <strong>{title}</strong>
    </div>
    <div>
      {description}
    </div>
  </Link>
)

src/component/item-list.js

import React from "react"

import Item from "./item"

import styles from "./item-list.module.css"

export default () => (
  <div className={styles.container}>
    <Item id={1} title="item 1" description="description 1" />
    <Item id={2} title="item 2" description="description 2" />
  </div>
)

src/component/item-list.module.css

.container {
  display: flex;
}

.container > * {
  background-color: aquamarine;
  width: 30%;
  margin: .75%;
  padding: .75%;
}

src/component/layout.module.css

.container {
  margin: 0;
  height: 100vh;
  display: grid;
  grid-template-columns: 200px 1fr;
}

.menu {
  background-color: #eee;
}

.content {
  padding: 8px;
}

src/component/menu.js

import React from "react"

export default () => (
  <ul>
    <li>Home</li>
    <li>Works</li>
  </ul>
)

ここまでのセットアップで、表面上はポートフォリオサイトができあがったように見える。

Next

次回はいよいよデータの取得と一覧ページの作成を行っていく。これまで固定で表示していた一覧が、データに沿って生成されるようになる。

gatsby