React 開発入門:基礎構文から状態管理およびルーティングまで

1. 開発環境の構築

1.1. プロジェクトの初期化

React アプリケーションを開始するには、公式のツールCHAIN を使用するのが一般的です。以下のコマンドを実行することで、必要な設定が含まれたプロジェクト構造が自动生成されます。

npx create-react-app my-first-react-app

ここで、my-first-react-app は任意のプロジェクト名に置き換えてください。作成が完了したら、以下のコマンドで開発サーバーを起動します。

npm start

なお、npx コマンドは npm パッケージを一時的に実行するためのツールであり、グローバルインストールの手間を省くことができます。最近では Vite などのより高速なビルドツールを利用するケースも増えています。

1.2. React の基本構造

React 18 以降では、レンダリング方法が若干変更されています。エントリーポイントファイル(通常は index.js)では、以下のように記述します。

import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App />);

従来の ReactDOM.render に代わり、createRoot を使用することで、React 18 の新機能である並列レンダリングに対応できます。

React の本質は、ユーザーインターフェースを構築するための JavaScript ライブラリです。主な特徴として、宣言的な UI 記述、コンポーネントベースのアーキテクチャ、そして学習した知識を Web だけでなくネイティブアプリ(React Native)にも応用可能な点が挙げられます。

2. JSX 構文の理解

2.1. createElement から JSX へ

本来、React 要素は React.createElement 関数で生成されますが、この記法は冗長で可読性が低いです。

// 従来の写法
const element = React.createElement('h1', { className: 'title' }, 'Welcome');

これを改善するために導入されたのが JSX(JavaScript XML)です。JSX を使用すると、HTML に似た構文で UI を記述できます。

// JSX による記述
const element = <h1 className="title">Welcome</h1>;

JSX はブラウザでは直接実行できないため、Babel などのトランスパイラを通じて通常の JavaScript コードに変換されます。

2.2. JSX の制約と規則

  • 単一のルート要素: 複数の要素を返す場合は、フラグメント(<>...</>)で囲む必要があります。
  • 属性名の違い: HTML の class 属性は、JavaScript の予約語と衝突するため className を使用します。同様に、forhtmlFor になります。
  • タグの閉じ方: 子要素を持たないタグは、必ず /> で閉じる必要があります(例:<img />)。
  • 式埋め込み: JSX 内に JavaScript 変数や式を埋め込む場合は、中括弧 { } で囲みます。

2.3. 動的なコンテンツ渲染

JSX 内では、変数、オブジェクトのプロパティ、配列の要素、関数の戻り値などを直接表示できます。

const userInfo = { name: 'Tanaka', age: 25 };
const skills = ['JavaScript', 'React', 'Node.js'];

const profile = (
  <div>
    <h2>{userInfo.name} - {userInfo.age} 歳</h2>
    <ul>
      {skills.map((skill, index) => (
        <li key={index}>{skill}</li>
      ))}
    </ul>
  </div>
);

リスト渲染時には、各要素に固有の key プロパティを付与することが性能最適化のために重要です。

2.4. 条件渲染とスタイル

三項演算子や論理演算子を使用して、条件に基づいて要素を表示・非表示できます。

const isLoggedIn = true;
const message = isLoggedIn ? <span>ようこそ</span> : <span>ログインしてください</span>;

// インラインスタイル
const boxStyle = { backgroundColor: 'lightblue', padding: '10px' };
const div = <div style={boxStyle}>コンテンツ</div>;

3. コンポーネントの作成

3.1. 関数コンポーネント

現代の React 開発では、関数コンポーネントが主流です。これは単なる JavaScript 関数であり、JSX を返します。

function Welcome(props) {
  return <h1>こんにちは、{props.name} さん</h1>;
}

矢印関数を用いて記述することも可能です。

3.2. クラスコンポーネント

以前のバージョンでは、状態管理やライフサイクルを利用するためにクラスコンポーネントが必須でした。現在でもレガシーコードで多く見られます。

import { Component } from 'react';

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

クラスコンポーネントは React.Component を継承し、render メソッドを実装する必要があります。

3.3. 状態(State)の管理

コンポーネント内部で変化するデータは「状態」と呼ばれます。クラスコンポーネントでは this.state で管理し、this.setState で更新します。

class Counter extends Component {
  state = { score: 0 };

  increment = () => {
    this.setState({ score: this.state.score + 1 });
  };

  render() {
    return (
      <div>
        <p>スコア:{this.state.score}</p>
        <button onClick={this.increment}>追加</button>
      </div>
    );
  }
}

関数コンポーネントでは、useState フックを使用して状態を扱います。

3.4. イベント処理

React のイベントハンドラは、DOM イベントに似ていますが、camelCase で記述し、関数を渡します。

<button onClick={handleClick}>クリック</button>

クラスコンポーネントでは、this のバインド問題に注意が必要です。クラスフィールド構文(矢印関数)を使用するか、コンストラクタでバインドすることで解決できます。

3.5. フォームの制御

React では、フォーム要素の値を state で管理する「制御コンポーネント」が推奨されます。

function LoginForm() {
  const [username, setUsername] = React.useState('');

  const handleChange = (e) => {
    setUsername(e.target.value);
  };

  return (
    <input value={username} onChange={handleChange} />
  );
}

これにより、入力値と React の状態が常に同期されます。

4. コンポーネント間のデータ連携

4.1. Props による受け渡し

親コンポーネントから子コンポーネントへデータを渡すには、プロパティ(props)を使用します。props は読み取り専用です。

// 親
<Child title="情報" count={5} />

// 子
function Child({ title, count }) {
  return <div>{title}: {count}</div>;
}

4.2. 子から親への通信

子コンポーネントから親へデータを伝えるには、親から関数を props として渡し、子からその関数を実行します。

// 親
const handleData = (data) => console.log(data);
<Child onSend={handleData} />

// 子
<button onClick={() => props.onSend('データ')}>送信</button>

4.3. Context API

深くネストされたコンポーネント間でデータを共有する場合、Context を使用すると props のバケツリレーを避けられます。

const ThemeContext = React.createContext('light');

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

5. ライフサイクルとフック

5.1. クラスのライフサイクル

クラスコンポーネントには、-mounting, updating, unmounting- の各段階で実行されるメソッドがあります。

  • componentDidMount: 初回渲染後。API リクエストなどに使用。
  • componentDidUpdate: 更新後。DOM 操作などに使用。
  • componentWillUnmount: 削除前。タイマーのクリアなどに使用。

5.2. Hooks の活用

関数コンポーネントでライフサイクルや状態を扱うためにフックが導入されました。

  • useState: 状態管理。
  • useEffect: 副作用処理(ライフサイクルの代替)。
  • useRef: DOM 要素や変数の参照。
useEffect(() => {
  //  mounting または updating 時
  const timer = setInterval(() => {}, 1000);
  return () => {
    // unmounting 時
    clearInterval(timer);
  };
}, [dependency]);

6. ルーティング(React Router v6)

シングルページアプリケーションにおける画面遷移には、React Router が標準的に使用されます。

6.1. 基本設定

import { BrowserRouter, Routes, Route } from 'react-router-dom';

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/about" element={<About />} />
  </Routes>
</BrowserRouter>

6.2. ナビゲーション

<Link> コンポーネントを使用すると、ページ遷移時に再読み込みを防げます。

<Link to="/about">詳細ページへ</Link>

プログラミング的な遷移には useNavigate フックを使用します。

7. 性能最適化

7.1. 不要な渲染の防止

親コンポーネントの更新が子コンポーネントの不要な再渲染を招くことがあります。React.memo を使用することで、props が変更された場合のみ渲染するように制御できます。

7.2. 状態の分割

関連性のないデータを一つの state オブジェクトにまとめるのではなく、複数の useState で管理するか、状態を分割することで、必要な部分のみ更新されるようにします。

7.3. 純粋コンポーネント

クラスコンポーネントでは PureComponent を使用することで、浅い比較に基づいた最適化を自動的に行えます。関数コンポーネントでは memo が同等の役割を果たします。

8. エラーハンドリングと拡張機能

8.1. エラーバウンダリ

子コンポーネントツリーで発生した JavaScript エラーをキャッチし、フォールバック UI を表示するには、エラーバウンダリクラスを作成します。getDerivedStateFromErrorcomponentDidCatch を実装します。

8.2. レンダープロップス

コンポーネントの再利用性を高める技法の一つです。props として関数を渡し、その関数の戻り値を渲染します。

<DataProvider render={(data) => <Child info={data} />} />

8.3. コード分割

React.lazySuspense を組み合わせることで、コンポーネントを動的にインポートし、バンドルサイズを削減できます。

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

タグ: React JSX react-hooks react-router state-management

7月19日 01:23 投稿