Nextjsチュートリアル2(コンポーネントとスタイル)

コンポーネントとレイアウト

各ページのレイアウトを以下のように統一したい。

(Contentsをページごとに切り替え)

そのためHeader、Footer、Layoutを決めるComponentを作成する。

  • まずは各コンポーネントを格納するフォルダを作成する。

フォルダ構成(好み)は「アプリのルート>src>components」とし、componentsフォルダの配下にfooter.tsx、header.tsx、pageLayout.tsxのファイルを作成する。

まずはHeaderコンポーネントを以下の内容で設定する。

  • Headタグ内にWebアプリのメタ情報を設定
  • ヘッダーの表示要素を作成(以下の例ではアイコンとアプリ名を中央揃え表示)
  • publicにimagesフォルダを作成し、アイコン用の画像を配置
import type { NextPage } from 'next';
import Head from 'next/head';
import Image from 'next/image';
import Link from 'next/link';
import styles from '/styles/Home.module.css';
import {
  APP_NAME,
  SITE_TITLE,
  HEADER_ICON_HEIGHT,
  HEADER_ICON_WIDTH,
} from '../app.const';

const Header: NextPage = () => {
  return (
    <>
      <Head>
        <title>{APP_NAME}</title>
        <link rel="icon" href="/favicon.ico" />
        <meta name="description" content="Vtuber Info App" />
        <meta
          property="og:image"
          content={`https://og-image.vercel.app/${encodeURI(
            SITE_TITLE
          )}.png?theme=light&md=0&fontSize=75px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg`}
        />
        <meta name="og:title" content={SITE_TITLE} />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1"
        ></meta>
      </Head>
      <div className={styles.header}>
        <Image
          priority
          src="/images/media-small-icon.svg"
          height={HEADER_ICON_HEIGHT}
          width={HEADER_ICON_WIDTH}
          alt={APP_NAME}
        />
        <h1 className={styles.headerText}>{APP_NAME}</h1>
      </div>
    </>
  );
};

export default Header;

Imageタグの使い方はリファレンスを参照。

使用している定数はsrcフォルダ配下にapp.const.tsを作成、以下のように定義を行う。

export const APP_NAME = 'Vtuber App';
export const SITE_TITLE = 'Vtuber Web Site';
export const HEADER_ICON_HEIGHT: number = 72;
export const HEADER_ICON_WIDTH: number = HEADER_ICON_HEIGHT;

続いてFooterを定義する。

こちらは一旦テンプレートのフッターをそのまま使用している。

import type { NextPage } from 'next';
import Head from 'next/head';
import Image from 'next/image';
import Link from 'next/link';
import styles from '/styles/Home.module.css';
import { APP_NAME, SITE_TITLE } from '../app.const';

const Footer: NextPage = () => {
  return (
    <>
      <footer className={styles.footer}>
        <a
          href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
          target="_blank"
          rel="noopener noreferrer"
        >
          Powered by{' '}
          <span className={styles.logo}>
            <Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
          </span>
        </a>
      </footer>
    </>
  );
};

export default Footer;

最後に画面全体のレイアウトを規定するコンポーネントクラスを作成する。

先ほど作成したHeaderコンポーネントとFooterコンポーネントを使用してレイアウトを規定する。各ページではこのコンポーネントを呼び出して各画面の要素を引数(children:子要素)で渡すことでレイアウトに埋め込んでいる。

import type { NextPage } from 'next';
import Footer from './footer';
import Header from './header';
import styles from '/styles/Home.module.css';

type Props = {
  children?: React.ReactNode;
};

const PageLayout: NextPage = ({ children }: Props) => {
  return (
    <>
      <Header />
      <div className={styles.container}>
        <main className={styles.main}>{children}</main>
      </div>
      <Footer />
    </>
  );
};

export default PageLayout;

ページでの使用例は以下の通り、PageLayoutコンポーネントで挟んだ内容が画面のヘッダーとフッターの間に埋め込まれる。

import type { NextPage } from 'next';
import Head from 'next/head';
import Image from 'next/image';
import Link from 'next/link';
import PageLayout from '../src/components/pageLayout';
import styles from '../styles/Home.module.css';

const Home: NextPage = () => {
  return (
    <PageLayout>
      <h1 className="title">Home</h1>
      <h2>
        <Link href="/list/vtuber">
          <a>Go List Page</a>
        </Link>
      </h2>
    </PageLayout>
  );
};

export default Home;

スタイル

cssのファイルはテンプレート作成時にstylesフォルダが作成されるのでその中に格納していく。テンプレートでは全体適用のcssファイル(globals.css)とCSSモジュールファイル(Home.modules.css)が作成されている。レイアウト調整のため以下モジュールファイルに設定している。

.container {
  max-width: auto;
  padding: 0 1rem;
  margin: 1rem 2rem;
  word-break: break-all;
}

.main {
  min-height: 60vh;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

@media (max-width: 480px) {
  .contents {
    overflow-wrap: normal;
  }
}

.header {
  display: -webkit-flex;
  display: flex;
  -webkit-justify-content: center;
  justify-content: center;
  -webkit-align-items: center;
  align-items: center;
  min-height: 10vh;
}

.headerText {
  margin-left: 30px;
}

NextはデフォルトでCSS in JSも使えるものの現状一旦スキップ。個別のページやコンポーネントでcss作りこみたくなった場合に使用する。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です