React

Facebookが開発したユーザーインターフェース構築のためのJavaScriptライブラリ。コンポーネントベースの設計により、再利用可能で保守性の高いUIを作成可能。

JavaScriptフレームワークFrontendUIコンポーネントVirtual DOM

フレームワーク

React

概要

Reactは、Facebookが開発したユーザーインターフェース構築のためのJavaScriptライブラリです。

詳細

React(リアクト)は2013年にFacebookによってオープンソース化された、宣言的で効率的、かつ柔軟なJavaScriptライブラリです。UIを構築するためのコンポーネントベースアーキテクチャを採用し、再利用可能なUIコンポーネントを作成できます。Virtual DOMという仮想的なDOM表現を使用することで、実際のDOM操作を最小限に抑え、高いパフォーマンスを実現しています。単方向データフローとステート管理により、予測可能で保守しやすいアプリケーション開発が可能です。JSXという拡張構文により、HTMLライクな記述でコンポーネントを定義でき、開発者体験が向上しています。現在では世界最大のフロントエンドエコシステムを持ち、Next.js、Gatsby、React Nativeなど多くの関連技術と組み合わせて使用されています。

メリット・デメリット

メリット

  • コンポーネントベース: 再利用可能なUIコンポーネントで保守性向上
  • Virtual DOM: 高いパフォーマンスと効率的なレンダリング
  • 豊富なエコシステム: 膨大なライブラリとツール群
  • 学習コミュニティ: 世界最大級の開発者コミュニティ
  • 企業サポート: Meta(Facebook)による継続的な開発とサポート
  • TypeScript対応: 型安全性による開発体験の向上
  • React DevTools: 優秀な開発・デバッグツール

デメリット

  • 学習コスト: JSX、フック、ステート管理など習得項目が多い
  • 急速な変化: 頻繁なアップデートとベストプラクティスの変更
  • 設定の複雑さ: 本格的なプロジェクトでは多くの設定が必要
  • SEOの課題: Client-Side Renderingによる検索エンジン最適化の問題
  • バンドルサイズ: 大規模アプリケーションでのバンドルサイズ増大

主要リンク

書き方の例

Hello World

// 関数コンポーネントの基本形
function HelloWorld() {
  return <h1>Hello, React!</h1>;
}

// アロー関数での記述
const HelloWorld = () => {
  return <h1>Hello, React!</h1>;
}

// レンダリング
import ReactDOM from 'react-dom/client';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<HelloWorld />);

コンポーネントとProps

// Propsを受け取るコンポーネント
function Welcome(props) {
  return <h1>こんにちは、{props.name}さん!</h1>;
}

// 分割代入を使った記述
function Welcome({ name, age }) {
  return (
    <div>
      <h1>こんにちは、{name}さん!</h1>
      <p>あなたは{age}歳ですね。</p>
    </div>
  );
}

// 使用例
function App() {
  return (
    <div>
      <Welcome name="太郎" age={25} />
      <Welcome name="花子" age={30} />
    </div>
  );
}

ステート管理(useState)

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  const decrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h2>カウンター: {count}</h2>
      <button onClick={increment}>+1</button>
      <button onClick={decrement}>-1</button>
      <button onClick={() => setCount(0)}>リセット</button>
    </div>
  );
}

エフェクト(useEffect)

import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // データの取得
    const fetchUser = async () => {
      setLoading(true);
      try {
        const response = await fetch(`/api/users/${userId}`);
        const userData = await response.json();
        setUser(userData);
      } catch (error) {
        console.error('ユーザーデータの取得に失敗:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchUser();
  }, [userId]); // userIdが変更されたときに再実行

  if (loading) return <div>読み込み中...</div>;
  if (!user) return <div>ユーザーが見つかりません</div>;

  return (
    <div>
      <h2>{user.name}</h2>
      <p>メール: {user.email}</p>
    </div>
  );
}

フォーム処理

import { useState } from 'react';

function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: value
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('送信データ:', formData);
    // API送信処理など
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="name">名前:</label>
        <input
          type="text"
          id="name"
          name="name"
          value={formData.name}
          onChange={handleChange}
          required
        />
      </div>
      <div>
        <label htmlFor="email">メール:</label>
        <input
          type="email"
          id="email"
          name="email"
          value={formData.email}
          onChange={handleChange}
          required
        />
      </div>
      <div>
        <label htmlFor="message">メッセージ:</label>
        <textarea
          id="message"
          name="message"
          value={formData.message}
          onChange={handleChange}
          rows={4}
          required
        />
      </div>
      <button type="submit">送信</button>
    </form>
  );
}

カスタムフック

import { useState, useEffect } from 'react';

// カスタムフック: データフェッチング
function useApi(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('データの取得に失敗しました');
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

// カスタムフックの使用例
function ProductList() {
  const { data: products, loading, error } = useApi('/api/products');

  if (loading) return <div>読み込み中...</div>;
  if (error) return <div>エラー: {error}</div>;

  return (
    <ul>
      {products?.map(product => (
        <li key={product.id}>
          {product.name} - {product.price}円
        </li>
      ))}
    </ul>
  );
}