サイトアイコン 【TechGrowUp】

Reactコンポーネント徹底ガイド──基本から応用パターンまでわかりやすく解説

はじめに

Reactを初めて学ぶ人が最初につまづきやすいのが「コンポーネント」の概念です。コンポーネントはUIを部品化し、再利用可能な塊として扱う手法。公式ドキュメント (https://react.dev/learn#components) では「コンポーネントは関数と同じ」と説明していますが、実際にコードを書くときにはPropsやState、Hooksと組み合わせるため、学習のハードルが高く感じられることもあります。本記事ではReact 18+最新情報を交え、関数コンポーネント、クラスコンポーネント、Props、State、Hooks、コンポジションや最適化パターンまで丁寧に解説します。

コンポーネントとは何か

コンポーネントは「UI部品」のようなもので、HTMLとJavaScriptを一体化して定義できます。例えば「ボタン」や「入力フォーム」のようなパーツを1つのファイルとして切り出し、 他の箇所から呼び出して使い回せるのが最大の利点です。

// Button.jsx
export function Button({ label, onClick }) {
  return <button onClick={onClick}>{label}</button>;
}

上記のように、Button コンポーネントを定義し、labelonClick をPropsで受け取ることで、使う場所ごとに見た目や挙動を変えられます。

関数コンポーネントの基礎

宣言方法

関数コンポーネントはJavaScriptの関数として定義し、必ず1つのJSX要素を返します。

function Greeting({ name }) {
  return <h1>こんにちは、{name}さん!</h1>;
}

ESLintやTypeScript環境では React.FC 型を使って型注釈を付けるケースもあります。

Propsの受け渡し

Propsはコンポーネントを呼び出す側で指定します。

<Greeting name="太郎" />
<Greeting name="花子" />

複数のPropsを使う場合はオブジェクト形式でまとめて受け取り、分割代入で取り出します。

function Profile({ avatarUrl, username, bio }) { /* … */ }

クラスコンポーネントとの違い

かつてReactはクラスコンポーネントが主流でした。2025年現在はHooksの登場で関数コンポーネントが主役ですが、既存コードやライフサイクルメソッドの学習に役立つため、基本を抑えておくと理解が深まります。

import React from 'react';

class Greeting extends React.Component {
  render() {
    return <h1>こんにちは、{this.props.name}さん!</h1>;
  }
}

Hooksを使えば同等の処理が関数コンポーネントで実現可能です。

Stateの扱い方

useStateフック

Stateは「変化する値」を保持し、再レンダーを引き起こす仕組みです。関数コンポーネントでは useState を使って簡単にStateを定義できます。

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <>
      <p>現在のカウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>増やす</button>
    </>
  );
}

Stateの注意点

const [todos, setTodos] = useState(() => loadTodosFromLocalStorage());

Props vs State

項目PropsState
定義場所親コンポーネントが渡す自身のコンポーネント内で定義
役割親からの読み取り専用の値パーツ内部で変化する値
更新親が再レンダーされる必要あり更新関数を呼ぶだけで自動的に再レンダー

Propsを変更したい場合は「親コンポーネント」が再レンダーされて新しいPropsを渡す仕組みになります。

コンポーネントの合成(Composition)

Reactではコンポジションが主流で、親子や兄弟のようにコンポーネントを入れ子にして機能を組み立てます。

function Card({ children }) {
  return <div className="card">{children}</div>;
}

function App() {
  return (
    <Card>
      <h2>タイトル</h2>
      <p>内容テキスト</p>
    </Card>
  );
}

ライフサイクルとuseEffect

useEffectの基本

副作用(データフェッチ、購読、手動DOM操作など)を扱う際に使うフック。

import { useEffect, useState } from 'react';

function DataFetcher({ url }) {
  const [data, setData] = useState(null);
  useEffect(() => {
    fetch(url)
      .then(r => r.json())
      .then(json => setData(json));
  }, [url]); // urlが変わったときだけ再実行
  return data ? <pre>{JSON.stringify(data)}</pre> : <p>読み込み中…</p>;
}
useEffect(() => {
  const id = setInterval(tick, 1000);
  return () => clearInterval(id);
}, []);

クラスのライフサイクル対応

パフォーマンス最適化

React.memo

関数コンポーネントをラップして、Propsが変わらない限り再レンダーを防ぐ。

const ExpensiveComponent = React.memo(function({ value }) {
  // 重い計算...
  return <span>{value}</span>;
});

useCallback / useMemo

const handleClick = useCallback(() => { /* ... */ }, [deps]);
const result = useMemo(() => expensiveCalculation(a, b), [a, b]);

Virtualized List

大量データをリスト表示する場合は react-windowreact-virtualized を使って、可視領域のみDOM生成する。

コンポーネント設計パターン

Container / Presentational

function UserContainer() {
  const [user, setUser] = useState(null);
  useEffect(() => fetchUser().then(setUser), []);
  return user ? <UserProfile data={user} /> : <Loading />;
}
function UserProfile({ data }) { /* UIのみ */ }

Compound Components

親コンポーネントと子要素が連携して振る舞うパターン。

function Tabs({ children }) {
  const [active, setActive] = useState(0);
  return /* contextでactiveとsetActiveを渡す */;
}
Tabs.List = function({ children }) { /* タブ見出し */ };
Tabs.Panel = function({ index, children }) { /* コンテンツ */ };

テストと型安全

テスト例(React Testing Library)

import { render, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('クリックで増加', () => {
  const { getByText } = render(<Counter />);
  const btn = getByText(/増やす/);
  fireEvent.click(btn);
  expect(getByText(/現在のカウント: 1/)).toBeInTheDocument();
});

TypeScriptとの併用

コンポーネントに型注釈を付けると、Propsのうっかりミスをコンパイル時に検出できます。

interface ButtonProps { label: string; onClick: () => void; }
export function Button({ label, onClick }: ButtonProps) { /* ... */ }

まとめ

Reactコンポーネントは「UIを部品化して組み合わせる」ための基本単位です。関数コンポーネントとクラスコンポーネントの違い、PropsとState、Hooks、コンポジション、最適化パターンをしっかり理解すれば、堅牢で再利用性の高いUIを効率的に開発できます。公式ドキュメントを自分のプロジェクトに落とし込む際には、ここで解説した多彩なパターンをぜひ試してみてください。

モバイルバージョンを終了