React × Next.js 実践開発入門 #5 Next.jsでアセット、メタデータ、CSSを扱う

公開日:2022-07-04
React
Next.js

https://www.youtube.com/watch?v=VL3Ig56uT9U

この講座はYouTubeで動画形式でも用意しています。合わせてご覧ください。

はじめに

前回は、Next.jsでのページ遷移の方法について学びました。今回は、次の内容について学びましょう。

また、最後により良いレイアウトの実践的な方法や、スタイリングのTipsも紹介します。

アセット

Webサイトを作る際には、画像やfavicon(ページのアイコン)などの素材が必要になります。これらをアセットといい、Next.jsがルート直下に用意するpublicというディレクトリの中にファイルを置いていきます。これらをアプリケーションの中から呼び出します。

例えば、Next.jsのプロジェクトを作った時点では、次のようにvercel.svgという画像ファイルを呼び出しています。

<img src="/vercel.svg" alt="Vercel Logo" className="logo" />

このvercel.svgは、publicディレクトリ内に配置されています。

メタデータ

メタデータとは、HTMLでheadタグ内に書かれるような情報で、ブラウザのページ表示領域に直接現れないような情報を指します。例えば次のようなものがあります。

  • ページタイトル
  • OGP (SNSやチャットでURLがシェアされた際に表示されるタイトルやサムネイルなどの設定)

Next.jsにはHeadコンポーネントが用意されています。次のようにインポートします。

import Head from 'next/head';

メタデータを制御したいページのコンポーネントで、Headコンポーネントを用います。

export default function Home() {
  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main> ... </main>
    </div>
  )
}

それぞれのページコンポーネントにHeadコンポーネント用いることで、ページごとに異なるタイトルも設定できます。

export default function FirstPost() {
  return (
    <>
      <Head>
        <title>First Post</title>
      </Head>
      ...
    </>
  )
}

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

続いては、レイアウトコンポーネントを学びます。Next.jsに限らず、共通コンポーネントを作成して複数箇所で再利用すると言う手法はよく使われます。

レイアウトコンポーネントの具体例を見てみましょう。ページを作成する際はpagesディレクトリにファイルを作成しましたが、今回はcomponentsディレクトリにLayout.tsxファイルを作成します。

import React from 'react';

const Layout: React.FC = ({ children }) => <div>{children}</div>

渡されたchildrenをdiv要素で括るだけのレイアウトコンポーネントが作成できました。このLayoutコンポーネントは、他のページコンポーネントなどで利用できます。

利用する際は、まずインポートが必要です。

import Layout from '@/components/Layout';
export default function FirstPost() {
  return (
    <Layout>
      <Head>...<Head>
      <h1>First Post</h1>

      ...

    </Layout>
  )
}

というように利用できます。この時点では、Layoutコンポーネントによって、ただdiv要素で括られているだけです。

CSSスタイリング

続いては、CSSによってページスタイルを指定する方法を学びます。Next.jsではいくつかCSSスタイリングの方法があります。主なものは次の通りです。

まずはstyled-jsxを見ていきましょう。CSS Modulesは後述します。

styled-jsx

https://github.com/vercel/styled-jsxhttps://github.com/vercel/styled-jsx

styled-jsxは、コンポーネント内にCSSを書く方法です。<style jsx></style>という形式で記述します。通常のCSSの書き方に近い方法です。この方法を用いると、コンポーネント内で閉じたスタイルになるため、他のコンポーネントに影響しないようにできます。

CSS Modules

https://github.com/css-modules/css-moduleshttps://github.com/css-modules/css-modules

CSS Modulesを用いて、共通コンポーネントにスタイルを当てていきます。こうすることで、共通コンポーネントが使われているすべての箇所で同じスタイルを適用できます。

先ほどはcomponents/Layout.tsxというファイルにレイアウトコンポーネントを作成しました。同じ階層にCSSファイルを作成しましょう。components/Layout.module.cssファイルを作成し、通常と同じようにCSSを記述します。

.container {
  max-width: 36rem;
  padding: 0 1rem;
  margin: 3rem auto 6rem;
}

このスタイルを利用しましょう。CSS Modulesもimport文で読み込ませることができます。Layout.tsxに追記します。

import styles from './Layout.module.css';

スタイルを当てる際には、先ほどのCSSファイルに記述したクラス名を用いて次のように記述します。

const Layout: React.FC = ({ children }) => (
  return <div className={styles.container}>{children}</div>
)

CSS Modulesを利用すると、CSSファイルをJSファイルから分離できるというメリットがあります。

グローバルCSS

コンポーネントごとに閉じたスタイルを当てることは非常に便利ですが、ページ全体に適用させたいスタイルもあります。こうしたスタイルはグローバルCSSと呼ばれル方法によって指定できます。

Next.jsでグローバルCSSを使う際は、_app.tsxという特別な名前のファイルを作成してコンポーネントを記述します。このコンポーネントは、Next.jsの全てのページコンポーネントに共通で用いられます。

import { AppProps } from 'next/app'
import '@styles/global.css'

export default App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

この2行目の部分がグローバルCSSをインポートしている部分です。通常のCSSファイルを作成してimport文でインポートすることによってページ全体に適用させるスタイルを指定できます。

より良いレイアウトの実践的な方法

ここまで、共通レイアウトやグローバルCSSについて学びました。より良いレイアウトをする方法を学びましょう。

三項演算子による表示切り替え

例えば、ホームページかどうかでヘッダーの表示を切り替えたいとします。homeという変数に応じて表示コンテンツを変えるには、三項演算子を用いた分岐を用います。

<header>
  {home ? (
    <> ... </>
  ) : (
    <> ... </>
  )}
</header>

Propsを用いた値渡し

共通コンポーネントとして利用する際にhomeをPropsを用いて受け取りたいので、Propsの型を定義します。?は省略可能を表します。

type Props = {home?: boolean}

const Layout = React.FC<Props> = ({ children, home }) => {
   ...
}

このLayoutコンポーネントを利用してみましょう。FirstPostページは一般のページなので単に<Layout>で括ります。

export default function FirstPost() {
  return (
    <Layout>
      <Head>
        <title>First Post</title>
      </Head>
      <h1>First Post</h1>
      ...
    </Layout>
  )
}

Homeページコンポーネントでは、homeというPropsを渡します。

export default function Home() {
  return (
    <Layout home>
      <Head>
        <title>{siteTitle}</title>
      </Head>
      <section>...</section>
    </Layout>
  )
}

コンポーネント以外の共通利用

コンポーネント以外にも共通で利用するものは、ファイルを分割してインポートによる利用ができます。
例えばHomeコンポーネントで見たsiteTitleは、Home.tsx内で定義しても良いですが、これをLayout.tsxに移してみましょう。

export const siteTitle = 'Next.js Sample Website'

Home.tsxではimport文によって利用します。

import Layout, { siteTitle } from '@/components/siteTitle'

このLayoutコンポーネントの全体像は、以下を参照してください。他にも今までに学んだ技術を利用しています。

  • <Head>コンポーネントによるメタデータを追加
  • <Link>コンポーネントによるページ遷移
  • CSS Modulesによるスタイリング

https://github.com/redimpulz/nextjs-react-training-blog/blob/master/components/Layout.tsxhttps://github.com/redimpulz/nextjs-react-training-blog/blob/master/components/Layout.tsx

スタイリングのTips

classnamesによるスタイル切り替え

classnamesは条件によってスタイルを切り替えたい場合に有用なライブラリです。

まずはスタイル適用前の状態のAlertという名前のコンポーネントを作成します。このコンポーネントはtypeというPropsを受け取るので、Propsの型定義を含めて次のように書けます。

import React from 'react';
import styles from './alert.module.css';

type Props = { type: 'success' | 'error' };

const Alert: React.FC<Props> = ({ children, type }) => {
  return (
    <div>
      {children}
    </div>
  );
};

export default Alert;

TypeScriptでは、単に文字列を表すにはtype: stringと記述すれば良いのですが、今回はtype: 'success' | 'error'と記述することで2通りの文字列に限定しています。

さて、classnamesを利用しましょう。classnamesは引数の右側に渡したオブジェクトの右側(値)に条件式を渡すことでtrueであれば左側(キー)のスタイルを適用させることができます。

まずはimport文を追加します。

import cn from 'classnames';

Propsのtype'success'であれば、CSSの.successクラスのスタイルが適用されるように、また'error'であっても同様に.errorが適用されるようにします。

const Alert: React.FC<Props> = ({ children, type }) => {
  return (
    <div
      className={cn({
        [styles.success]: type === 'success',
        [styles.error]: type === 'error',
      })}
    >
      {children}
    </div>
  );
};

PostCSSによるCSSの効率化

https://github.com/postcss/postcsshttps://github.com/postcss/postcss

PostCSSは、設定を記述しておくことによって、設定に応じてCSSを自動で加工できます。LESSやSassと似たようなツールになります。

また、PostCSSを使ったCSSのツールがいくつかあり、その1つにtailwindcssがあります。

https://tailwindcss.comhttps://tailwindcss.com

PostCSSを用いるにはいくつかのライブラリをインストールする必要があります。

npm install -D tailwindcss autoprefixer postcss

PostCSSの設定ファイルpostcss.config.jsを作成します。

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

tailwindcssの設定ファイルtailwind.config.jsも作成します。

module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
};

準備が整えば、tailwindcssの記法を用いて、tailwindcssのスタイルが適用されたボタンを作成できます。

<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
  Button
</button>

Sass

https://sass-lang.comhttps://sass-lang.com

SassはCSSの構文を拡張し、より便利に記述できるようにしたものです。

yarn add sass

でインストールするだけで利用可能になります。あとはCSS Modulesの拡張子を、.cssから.scssに変更するだけで利用できます。

まとめ

今回は、アセットやメタデータ、スタイリングを学習しました。
次回は事前レンダリングや静的生成、データ取得について学びます。