コンポーネントとは

コンポーネントとは、再利用可能な部品でありウェブページを構成する要素のことです。

シンプルに「部品」と理解すればいいかと思います。例えば、ヘッダー、フッター、メインコンテンツなどがコンポーネントになります。コンポーネントを使うことで、ウェブページを構成する要素を再利用できるようになります。また、コンポーネントを使うことで、ウェブページの構成を把握しやすくなります。

メリットは概ね次の通りです。

  • 疎結合になる(部品の再利用が容易になる)
  • コードの可読性が向上する
  • テストが簡単になる

コンポーネント設計のコツは、次の 2 つです。

  • 再利用性を高めるために抽象的に書く
  • 外部から情報を渡せるようにする

要は「使いまわしてなんぼ」ということです。できるだけアプリケーションのコンテキストに依存させない形で実現することを心がけましょう。

状態管理

コンポーネントには、状態を持たせることができます。状態を持たせることで、コンポーネントの振る舞いを変えることができます。状態を持たせることで、コンポーネントの再利用性を高めることができます。次の 2 つを使って状態を管理します。

props:

親コンポーネントから子コンポーネントへ情報を渡すために使用されるオブジェクトです。これにより、コンポーネントの外から値を受け取ることができます。React では単一方向データフローが推奨されており、親コンポーネントから子コンポーネントへのデータの流れが一方向になっています。

props は読み取り専用のオブジェクトです。そして、コンポーネントの中で書き換えることはできません。

props.children:

これは、コンポーネントの開始タグと終了タグの間にある要素を表します。この要素は、props.children として子コンポーネントでアクセスできます。例えば、<Header>ここに入る</Header> というコンポーネントがある場合、ここに入るが props.children になります。これにより、コンポーネント内で子要素を簡単に扱うことができます。

// components/CustomHeader.tsx
import React, { ReactNode } from 'react'

interface CustomHeaderProps {
  title: string
  children: ReactNode
}

const CustomHeader = ({ title, children }: CustomHeaderProps) => {
  return (
    <div>
      <h1>{title}</h1>
      <div>{children}</div>
    </div>
  )
}

export default CustomHeader

この例では、CustomHeader コンポーネントが title と children の 2 つの props を受け取ります。title は文字列であり、children は ReactNode 型です。

pages ディレクトリにある index.tsx ファイルを編集して、CustomHeader コンポーネントを使用します。

// pages/index.tsx
import type { NextPage } from 'next'
import CustomHeader from '../components/CustomHeader'

const Home: NextPage = () => {
  return (
    <div>
      <CustomHeader title="Welcome to My App">
        <p>This is a description under the header.</p>
      </CustomHeader>
    </div>
  )
}

export default Home

これらを使うことで、データは上から下方向へ渡され、逆方向に流れないので予期しない副作用を回避できます。

他に、Context API や Redux などの状態管理ライブラリを使うこともできます。Context は、コンポーネントツリー全体で共有されるデータです。props はバケツリレーで情報を渡しますが、Context は、情報をコンポーネントを横断して表示させることができます。

ヘッダーコンポーネント

ヘッダーコンポーネントは、ウェブページの上部に表示されるナビゲーション要素を含むコンポーネントです。通常、サイトのロゴ、メニュー、検索ボックスなどが含まれます。このセクションでは、Next.js と TypeScript を用いてヘッダーコンポーネントを作成する方法を解説します。

components というディレクトリを作成し、その中に Header.tsx というファイルを作成します。Header.tsx には、次のコードを記述します。コンポーネントの名前は大文字から始めるようにしましょう。

// components/Header.tsx
import React from 'react'
import Link from 'next/link'
import styles from './Header.module.css'

type HeaderProps = {
  title: string
}

const Header = ({ title }: HeaderProps) => {
  return (
    <header className={styles.header}>
      <h1>{title}</h1>
      <nav>
        <ul>
          <li>
            <Link href="/">
              <a>Home</a>
            </Link>
          </li>
          <li>
            <Link href="/about">
              <a>About</a>
            </Link>
          </li>
        </ul>
      </nav>
    </header>
  )
}

export default Header

上記のコードは、Header.tsx というファイルに記述されています。HeaderProps という型を定義して、title というプロパティを持たせています。Header コンポーネントは、React.FC 型を使って定義されており、受け取った title を表示します。また、Link コンポーネントを使って、ページ間のリンクを設定しています。

フッターコンポーネント

フッターコンポーネントは、ウェブページの下部に表示される情報をまとめたコンポーネントです。通常、コピーライト、プライバシーポリシー、利用規約、連絡先などが含まれます。このセクションでは、Next.js と TypeScript を用いてフッターコンポーネントを作成する方法を解説します。

// components/Footer.tsx
import React from 'react'
import styles from './Footer.module.css'

const Footer = () => {
  return (
    <footer className={styles.footer}>
      <p>&copy; 2023 Your Company. All rights reserved.</p>
    </footer>
  )
}

export default Footer

上記のコードは、Footer.tsx というファイルに記述されています。Footer コンポーネントは、React.FC 型を使って定義されており、コピーライト情報を表示します。CSS モジュールを使って、スタイルを適用しています。

FV コンポーネント

FV(First View)コンポーネントは、ウェブページの最初に表示される部分を担当するコンポーネントです。通常、大きな画像やキャッチフレーズ、コールトゥアクションボタンなどが含まれます。このセクションでは、Next.js と TypeScript を用いて FV コンポーネントを作成する方法を解説します。

// components/FV.tsx
import React from 'react'
import styles from './FV.module.css'

type FVProps = {
  imageUrl: string
  altText: string
  catchphrase: string
  buttonText: string
}

const FV = ({ imageUrl, altText, catchphrase, buttonText }: FVProps) => {
  return (
    <section className={styles.fv}>
      <img src={imageUrl} alt={altText} />
      <h2>{catchphrase}</h2>
      <button>{buttonText}</button>
    </section>
  )
}

export default FV

上記のコードは、FV.tsx というファイルに記述されています。FVProps という型を定義して、imageUrlaltTextcatchphrasebuttonText というプロパティを持たせています。FV コンポーネントは、React.FC 型を使って定義されており、受け取ったプロパティを適切に表示します。CSS モジュールを使って、スタイルを適用しています。

コンポーネントの組み合わせ

これらのコンポーネントを組み合わせて、ページ全体を構築します。例として、pages/index.tsx というファイルでヘッダー、FV、フッターを組み合わせて表示する方法を解説します。

// pages/index.tsx
import React from 'react'
import Header from '..components/Header'
import FV from '..components/FV'
import Footer from '..components/Footer'

const Home = () => {
  return (
    <div>
      <Header title="プログラミング教材ページ" />
      <FV imageUrl="/images/programming.jpg" altText="プログラミング画像" catchphrase="最高のプログラミング教材を提供します!" buttonText="今すぐ始める" />
      <Footer />
    </div>
  )
}

export default Home

上記のコードでは、HeaderFVFooter コンポーネントをインポートし、それぞれに適切なプロパティを渡して使用しています。これにより、ヘッダー、FV、フッターが組み合わされたページが完成します。Home コンポーネントは、React.FC 型を使って定義されており、各コンポーネントを表示しています。

Layout コンポーネント

ブログサイトには全ページにヘッダーとフッターが入ります。そして、その間には各ページのコンテンツが表示されます。このような共通のレイアウトを管理するために、Layout コンポーネントを作成します。

touch components/Layout.tsx

以下の例では、Emotion を使いますが、インストールしていない人は次のコマンドでインストールしてください。

npm install --save typescript @types/react @types/node @emotion/react @emotion/styled

Layout.tsx の内容は次のようになります。

import { ReactNode } from 'react'
import styled from '@emotion/styled'

const Container = styled.div`
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 15px;
`

const Header = styled.header`
  padding: 20px 0;
  background-color: #333;
  color: #fff;
`

const Footer = styled.footer`
  padding: 20px 0;
  background-color: #333;
  color: #fff;
`

type LayoutProps = {
  children: ReactNode
}

const Layout = ({ children }: LayoutProps) => (
  <>
    <Header>My Blog</Header>
    <Container>{children}</Container>
    <Footer>&copy; {new Date().getFullYear()} My Blog</Footer>
  </>
)

export default Layout

そして、index.tsx で Layout コンポーネントを使います。

import Layout from '..components/Layout'

const Home = () => {
  return (
    <Layout>
      <h1>Welcome to My Blog</h1>
      <p>This is a sample blog site built with Next.js, TypeScript, and Emotion.</p>
    </Layout>
  )
}

export default Home

このように、Next.js と TypeScript を使って、ヘッダー、フッター、FV のようなコンポーネントを作成し、ページ全体を構築することができます。コンポーネントを分割して管理することで、コードの再利用性やメンテナンス性が向上し、効率的に開発を進めることができます。この解説を参考にして、独自のウェブページを構築してみてください。