React開発における基本コンセプトと実践手法

Reactエコシステムの準備

Reactアプリケーションを開発する際、以下のツール群が広く利用されています。

  • React公式ドキュメント(日本語): コアフレームワークの学習に最適
  • React Router: ページ遷移やルーティング機能を提供
  • Zustand: 軽量な状態管理ライブラリ
  • TanStack Query: 非同期データ取得とキャッシュ管理
  • Vite: 高速ビルドとホットリロードを実現するモダンなビルドツール
  • Ant Design / FontAwesome: UI部品やアイコンの提供

プロジェクトの初期化

まずViteを使用して新しいReactプロジェクトを作成します。

npm create vite@latest my-react-app --template react
cd my-react-app
npm install
npm run dev

この手順により、JSX変換、モジュールバンドリング、開発サーバーが即座に利用可能になります。

仮想DOMの理解

Reactはレンダリングプロセスにおいて「仮想DOM」を中核としています。これは実際のブラウザDOMの軽量なJavaScriptオブジェクト表現です。

  • 変更の差分を効率的に計算し、最小限の再描画を行う
  • パフォーマンス向上と一貫したUI更新を実現
  • 開発者は直接DOM操作を行わず、状態に基づいてビューを宣言的に記述

JSX構文のルール

JSXはHTMLに似た構文で、JavaScriptの中に埋め込むことができます。主な規則:

  • 属性名はclassNamehtmlForのようにキャメルケースで記述
  • インラインスタイルはstyle={{ fontSize: '16px' }}のようなオブジェクト形式
  • 式の挿入には{}を使用(例:{user.name}
  • ルート要素は単一のタグで囲む必要がある
  • 自己終了タグは常に/>で閉じる(例:<img />

関数型コンポーネントと状態管理

現代のReactでは関数型コンポーネントが主流です。Hooksを用いることでクラスコンポーネントと同等の機能を実現できます。

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('Default');

  const increment = () => {
    // 正確な値を保証するため、関数形式で更新
    setCount(prev => prev + 1);
  };

  return (
    <div>
      <p>現在のカウント: {count}</p>
      <button onClick={increment}>+1</button>
      <p>名前: {name}</p>
    </div>
  );
}

副作用の管理: useEffect

useEffectはコンポーネントのマウント・更新・アンマウント時に処理を実行するためのフックです。

import { useEffect, useState } from 'react';

function DataFetcher() {
  const [data, setData] = useState(null);

  useEffect(() => {
    // 初期読み込み時のみ実行(依存配列を空に)
    fetch('/api/data')
      .then(res => res.json())
      .then(setData);

    // クリーンアップ関数(オプション)
    return () => {
      console.log('コンポーネントがアンマウントされました');
    };
  }, []); // 空の依存配列=初回レンダリング時のみ

  return <div>{data ? data.message : '読み込み中...' }</div>;
}

パフォーマンス最適化手法

不要な再レンダリングを防ぐために以下の方法があります。

React.memo

親コンポーネントの状態変更でも、子コンポーネントのpropsが変わっていなければ再レンダリングをスキップします。

const MemoizedChild = React.memo(function Child({ name }) {
  console.log('子コンポーネントがレンダリングされました');
  return <div>こんにちは、{name}さん!</div>;
});

useCallback

関数の参照を安定させることで、その関数をpropsに受け取る子コンポーネントの不要な再レンダリングを防ぎます。

function Parent() {
  const [value, setValue] = useState('');

  // 参照が維持されるように関数をラップ
  const handleChange = useCallback((e) => {
    setValue(e.target.value);
  }, []);

  return <MemoizedChild onChange={handleChange} />;
}

useMemo

高コストな計算結果をキャッシュし、依存値が変更されたときだけ再計算します。

function ExpensiveComponent({ list, filter }) {
  const filteredList = useMemo(() => {
    return list.filter(item => item.includes(filter));
  }, [list, filter]); // listまたはfilterが変更されたときのみ再実行

  return <ul>{filteredList.map(...)}</ul>;
}

コンテキストによる状態共有

深いネストでのprops渡しを避けるために、Context APIを使用できます。

import { createContext, useContext } from 'react';

const ThemeContext = createContext();

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div className={theme}>現在のテーマ: {theme}</div>;
}

遅延読み込み (Lazy Loading)

コード分割と動的読み込みにより、初期ロード時間を短縮できます。

import { lazy, Suspense } from 'react';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback=<div>読み込み中...</div>>
      <HeavyComponent />
    </Suspense>
  );
}

スタイリング戦略

Reactアプリケーションでは複数のスタイリングアプローチが存在します。

  • CSS Modules: filename.module.cssで作成し、自動的にスコープが隔離
  • Styled-components: JavaScript内にCSSを記述、動的プロパティ対応
  • Utility-first CSS (Tailwind): 小さなクラスを組み合わせてデザイン

一般的には、インラインスタイルは動的スタイルに限定し、静的スタイルは外部CSSファイルで管理することが推奨されます。

タグ: React Vite JSX Hooks useEffect

8月25日 06:51 投稿