コンテンツにスキップ

React.js

出典: フリー教科書『ウィキブックス(Wikibooks)』
Wikipedia
Wikipedia
ウィキペディアReactの記事があります。

React.jsは、柔軟で効果的なフロントエンドライブラリで、Webアプリケーションの構築において人気を博しています。本ガイドでは、React.jsの基本的な概念から始め、JSXやコンポーネントの作成、プロパティとステートの管理、イベント処理、条件付きレンダリングなど、幅広いトピックにわたります。初心者向けに、Node.jsとnpmのインストールから始まり、Reactアプリケーションのセットアップ、最新のTypeScriptを取り入れた開発もカバーします。各セクションには実際のコード例や実践的な演習が含まれ、手を動かしながら学べるよう工夫されています。React.jsを使用して効率的かつモダンなフロントエンドアプリケーションを構築するスキルを身につけ、最終的には実践プロジェクトを通じて習得した知識を活かすことが目標です。

はじめに

[編集]

React.jsは、Meta(以前のFacebook)が開発したUIライブラリで、柔軟かつ効率的なユーザーインターフェースを構築するために利用されます。本チュートリアルでは、React.jsの基本から学び、TypeScript(TSX)を組み合わせて実際のプロジェクトを構築する手順を紹介します。

React.jsとは

[編集]

React.jsは、コンポーネントベースのアーキテクチャと仮想DOMを使用して、効果的かつ柔軟なUIを構築するためのライブラリです。コンポーネントは再利用可能な部品であり、個々の状態を持っています。

仮想DOM

[編集]

Reactの仮想DOM(Virtual DOM)は、実際のDOMと同じ構造を持つが、ブラウザ上には直接表示されず、メモリ上に存在します。UIが変更されると、仮想DOMが新しいUI状態を反映し、実際のDOMと比較して変更点を効率的に見つけ出します。そして、変更が必要な部分のみを実際のDOMに適用し、再描画のコストを最小限に抑えます。

仮想DOMの使用は、UIのパフォーマンス向上や開発者が直感的にUIを更新できるようにするなど、Reactのコア技術の一部として重要です。

TypeScript

[編集]

TypeScriptはJavaScriptに型を導入した拡張言語で、開発プロセスを効果的にし、コードの品質を向上させます。ReactとTypeScriptを組み合わせることで、より安全でメンテナブルなコードを書くことができます。型エラーの早期発見やIDEのサポートを受けることで、開発効率が向上し、信頼性の高いアプリケーションを構築できます。

TypeScriptも、JSXと呼ばれるJavaScriptの拡張構文と同様に、TSXと呼ばれるTypeScriptの拡張構文を持っています。 これらの基本的な概念を理解した上で、React.jsとTypeScriptを使用したフロントエンド開発に進んでいきましょう。

React.jsとReact Native
React.js(またはReact)とReact Nativeは、Meta(以前のFacebook)によって開発されたJavaScriptライブラリで、ユーザーインターフェースを構築するために使用されます。それぞれのフレームワークは異なるプラットフォームでのアプリケーション開発に焦点を当てています。
React.js
React.jsは、Webアプリケーションの開発に特化したライブラリです。以下は、React.jsの主な特徴です。
Webアプリケーション開発
React.jsは、動的なユーザーインターフェースを構築するために使用されます。シングルページアプリケーション(SPA)の開発に適しています。
コンポーネントベース
React.jsはコンポーネントベースのアーキテクチャを採用しており、UIを小さな再利用可能な部品に分割します。これにより、コードのメンテナンス性が向上します。
Virtual DOM
React.jsは仮想DOM(Virtual DOM)を使用して、効率的かつ高速にUIを更新します。これにより、必要な部分だけが再描画され、パフォーマンスが向上します。
JSX
React.jsでは、JSX(JavaScript XML)を使用してコンポーネントの見た目を記述します。JSXはXML構文をJavaScriptに組み込むことができる構文拡張です。
React Native
React Nativeは、モバイルアプリケーションの開発に特化したフレームワークです。以下は、React Nativeの主な特徴です。
モバイルアプリケーション開発
React NativeはiOSおよびAndroidプラットフォームで動作するネイティブなモバイルアプリケーションを開発するためのフレームワークです。
コンポーネントベース
React NativeもReact.jsと同様に、コンポーネントベースのアーキテクチャを使用します。React.jsで作成したコンポーネントを一部再利用できるため、開発効率が向上します。
ネイティブAPIのアクセス
React Nativeアプリケーションは、JavaScriptを使用してネイティブAPIにアクセスできます。これにより、ネイティブな機能やモジュールを組み込むことが可能です。
Hot Reloading
React NativeはHot Reloadingをサポートしており、アプリケーションのコード変更をリアルタイムで反映させることができます。
共通点
React.jsとReact Nativeは、以下の点で共通しています。
ReactMeta(以前のFacebook)
両者ともReactコンポーネントのアーキテクチャを採用しており、コンポーネントを再利用することができます。
React生態系
React.jsとReact Nativeは、同じ生態系を共有しています。開発者はReactの基本的な概念を学び、両方のプラットフォームでコードを再利用できます。
一貫性
React.jsで開発したスキルや知識は、React Nativeの開発にも適用できます。これにより、同じ開発者がWebアプリケーションとモバイルアプリケーションの両方を開発できます。

React.jsとReact Nativeは、それぞれの特性に応じて異なる使用ケースで活躍します。開発者はプロジェクトの要件に基づいて、どちらを選択するかを検討する必要があります。

本書では、React.js を扱い React Native は扱いません。

Node.jsとnpmの導入

[編集]

React.jsの開発には、Node.jsとnpmのインストールが必要です。以下は、簡単な手順です。

Node.jsのインストール

[編集]
  1. Node.jsの公式ウェブサイトを訪れます。
  2. ウェブサイトから最新バージョンのNode.jsインストーラーをダウンロードします。
  3. ダウンロードしたインストーラーを実行して、指示に従ってNode.jsをインストールします。

npmパッケージの管理

[編集]

npmはNode.jsのパッケージマネージャで、React.jsプロジェクトの依存関係や開発ツールを管理します。npmの基本的な使い方について学びましょう。

  1. プロジェクトの初期化
    新しいReact.jsプロジェクトを作成するには、コマンドラインでプロジェクトのディレクトリに移動し、次のコマンドを実行します。
    npx create-react-app my-react-app
    
    これにより、基本的なReactアプリケーションのテンプレートが作成されます。
  2. パッケージの追加
    Reactアプリケーションには様々なパッケージが利用されます。例えば、TypeScriptを導入する場合、次のようにして追加します。
    npm install --save typescript @types/react @types/react-dom
    
    このコマンドは、TypeScriptとReact用の型定義をプロジェクトに追加します。
  3. パッケージの削除
    不要になったパッケージを削除するには、次のようにコマンドを実行します。
    npm uninstall パッケージ名
    

これで、Node.jsおよびnpmの基本的な使い方とパッケージの管理方法についての理解ができました。次に、React.jsとTypeScriptを使った最初のコンポーネントを作成していきましょう。

開発環境のセットアップ

[編集]

Create React Appを使用して新しいプロジェクトを作成

[編集]

React.jsの開発には、Create React Appを使用して新しいプロジェクトを作成することが一般的です。Create React Appは、Reactアプリケーションを簡単かつ迅速にセットアップするための公式なツールです。

Create React Appを使用して新しいプロジェクトを作成

[編集]
  1. Create React Appのインストール Create React Appをインストールするには、以下のコマンドを実行します。
    npx create-react-app my-react-app
    
    my-react-appは作成するプロジェクトの名前で、この部分を任意の名前に変更できます。
  2. プロジェクトディレクトリに移動 Create React Appで生成されたプロジェクトのディレクトリに移動します。
    cd my-react-app
    
  3. 開発サーバーの起動 開発サーバーを起動し、Reactアプリケーションをローカルで実行するには、以下のコマンドを実行します。
    npm start
    
    ブラウザで http://localhost:3000 にアクセスすると、Reactアプリケーションが表示されます。

Create React Appを使用することで、設定ファイルやビルドプロセスについて心配することなく、Reactアプリケーションの開発を素早く始めることができます。次に、Reactコンポーネントの基本的な作成と表示について学びましょう。

JSXとTSXの基本

[編集]

Reactでは、JSX(JavaScript XML)構文を使用してコンポーネントを記述します。JSXはXML構文のような記法で、JavaScriptの拡張です。TypeScriptを使用する場合は、TSX(TypeScript XML)を使用します。

以下は、基本的なJSXの例です。

elm.jsx
const element = <h1>Hello, React!</h1>;

JSXでは、HTMLタグのような構文が使用されていますが、これはReact.createElement()関数によってコンパイルされ、React要素が作成されます。

TSXでは以下のようになります。

elm.tsx
const element: JSX.Element = <h1>Hello, React!</h1>;

TSXでは、JSX要素の型アノテーションが通常必要です。型アノテーションはJSX.Elementを使用して、変数elementがJSX要素であることを示しています。

TypeScriptのTSXでは通常、型推論が十分に効果的に機能します。変数の型を明示的に指定せずに宣言すると、TypeScriptは初期化された値からその変数の型を推論します。以下は、型推論が可能な例です。

elm-ti.tsx
const element = <h1>Hello, React!</h1>;

この場合、TypeScriptは変数elementの型を自動的にJSX.Elementと推論します。型推論を利用することでコードは簡潔になり、冗長な型アノテーションを回避できます。ただし、特定の場面で型を明示的に指定することが望ましい場合もあります。

コンポーネント

[編集]

コンポーネント(Component)は、React.jsにおいてUIを構築するための基本的な部品です。Reactアプリケーションは、これらのコンポーネントから構成され、個々のコンポーネントは再利用可能な単位として機能します。

具体的には、コンポーネントは次のような特徴を持っています:

再利用可能性
コンポーネントは独立して機能し、他の部分で再利用できるように設計されます。これにより、コードの保守性が向上し、効率的な開発が可能となります。
状態(State)
コンポーネントは内部で状態を管理できます。状態はコンポーネントが保持するデータであり、それに基づいて動的なUIの変更が可能です。
プロパティ(Props)
親コンポーネントから子コンポーネントにデータを渡すためのプロパティが使用されます。これにより、コンポーネント間で情報を共有できます。
ライフサイクルメソッド
コンポーネントはマウント(Mount)、アップデート(Update)、アンマウント(Unmount)などのライフサイクルメソッドを持ちます。これらのメソッドを利用して、特定のタイミングでコードを実行できます。
JSX
Reactコンポーネントは通常、JSX(JavaScript XML)構文を使用して記述されます。JSXはHTMLライクな構文で、JavaScriptコード内にXML構造を記述することができます。また、JavaScriptに型アノテーションなどを追加したTypeScriptを同様に拡張してTSX(TypeScript XML)構文を使用して記述することもできます。

コンポーネントは小さな部品から大きなアプリケーションまで、Reactの柔軟性と拡張性を提供する重要な概念です。

コンポーネントの作成と表示

[編集]

Reactコンポーネントは、単純な関数またはクラスとして定義できます。以下は、関数コンポーネントの例です。

import React from 'react';

function MyComponent() {
  return <div>Hello, I'm a React component!</div>;
}

// このようにも書けます
const MyComponent2 () => <div>Hello, I'm a React component!</div>;

また、同様のコンポーネントをクラスとしても書くことができます。

import React, { Component } from 'react';

class MyComponent extends Component {
  render() {
    return <div>Hello, I'm a React component!</div>;
  }
}

これらのコンポーネントは、他のコンポーネントから呼び出して再利用できます。また、これをReactDOMを使ってHTMLにレンダリングすることができます。

import React from 'react';
import ReactDOM from 'react-dom';

const element = <MyComponent />;
ReactDOM.render(element, document.getElementById('root'));

この例では、MyComponentコンポーネントを<div id="root"></div>にレンダリングしています。

ReactDOM

ReactDOMは、React.jsで仮想DOMを実際のDOMに反映させるためのライブラリです。Reactアプリケーションでは、仮想DOMを使用してUIの変更を効率的に処理し、その変更をブラウザ上の実際のDOMに反映させます。ReactDOMは、この仮想DOMと実際のDOMの橋渡しを行います。

以下は、ReactDOMが使用される基本的な使い方です。

  1. DOMに描画する: Reactで構築されたUIを実際のDOMに描画するためには、ReactDOM.render()メソッドを使用します。これにより、Reactのコンポーネントツリーがブラウザ上のDOMに反映されます。
    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    
    ReactDOM.render(<App />, document.getElementById('root'));
    
    上記の例では、<App />というReactコンポーネントを、IDが 'root' である実際のDOMの要素に描画しています。
  2. 動的な変更を反映する: アプリケーションが実行されている間に状態が変化したり、データが更新された場合、ReactDOM.render()を再度呼び出すことで変更を反映させます。
    import React, { useState } from 'react';
    import ReactDOM from 'react-dom';
    
    function Counter() {
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <p>{count}</p>
          <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
      );
    }
    
    ReactDOM.render(<Counter />, document.getElementById('root'));
    
    この例では、useStateフックを使用してコンポーネントの状態を管理しており、ボタンがクリックされるたびに状態が変更されて再描画が行われます。

ReactDOMはReactの一部であり、Reactが提供する重要なツールの一つです。DOMの描画や再描画の際には、ReactDOMを使用して実際のDOMとReactの仮想DOMを連携させることが不可欠です。

次に、プロパティとステートについて学びながら、Reactコンポーネントのより高度な機能を探っていきましょう。

プロパティとステート

[編集]

Reactコンポーネントでは、プロパティ(Props)とステート(State)という二つの主要な概念があります。これらを活用することで、コンポーネントは動的で柔軟な振る舞いを示すことができます。

プロパティの受け渡し

[編集]

プロパティは、親コンポーネントから子コンポーネントに情報を渡すための仕組みです。関数コンポーネントでは引数としてpropsオブジェクトを受け取り、クラスコンポーネントではthis.propsを使用します。

// 関数コンポーネント
function MyComponent(props) {
  return <div>Hello, {props.name}!</div>;
}

// クラスコンポーネント
class MyComponent extends React.Component {
  render() {
    return <div>Hello, {this.props.name}!</div>;
  }
}

// 使用例
const element = <MyComponent name="John" />;

上記の例では、MyComponentnameというプロパティを渡しています。このようにして、動的なデータをコンポーネントに受け渡すことができます。

ステートの管理

[編集]

ステートは、コンポーネント内で管理される状態を表します。ステートは主にクラスコンポーネントで使用され、this.stateを通じてアクセスされます。コンポーネントが内部で保持するデータが変更されると、Reactは自動的に再レンダリングします。

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  increment() {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.increment()}>Increment</button>
      </div>
    );
  }
}

上記の例では、Counterコンポーネントが内部でcountというステートを持ち、ボタンがクリックされるとincrementメソッドが呼び出され、ステートが更新されます。この更新により、<p>要素内の表示が変更されます。

これらの概念を理解した上で、イベントハンドリングや条件付きレンダリングなどの応用的なトピックに進んでいきましょう。

イベントハンドリング

[編集]

Reactコンポーネントでは、ユーザーの操作に応じてイベントを処理することが一般的です。これにはクリック、入力、フォーム送信などの様々なイベントが含まれます。イベントハンドリングは、Reactのコンポーネント内で関数を作成し、それをイベントに対して呼び出す形で行います。

イベントの処理

[編集]

以下は、ボタンがクリックされたときにアラートを表示する単純な例です。

import React from 'react';

class MyButton extends React.Component {
  handleClick() {
    alert('Button clicked!');
  }

  render() {
    return <button onClick={() => this.handleClick()}>Click me</button>;
  }
}

上記の例では、handleClickメソッドがボタンがクリックされたときに呼び出されます。onClickプロパティには、関数が渡されていることに注意してください。アロー関数を使用することで、thisの参照が正しくなります。

ステートの更新

[編集]

イベントハンドリングによく使用されるパターンは、ステートの更新です。例として、フォームの入力値をステートに保存し、動的に反映する場合を考えてみましょう。

import React from 'react';

class InputForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = { inputValue: '' };
  }

  handleChange(event) {
    this.setState({ inputValue: event.target.value });
  }

  render() {
    return (
      <div>
        <input
          type="text"
          value={this.state.inputValue}
          onChange={(event) => this.handleChange(event)}
        />
        <p>You typed: {this.state.inputValue}</p>
      </div>
    );
  }
}

この例では、<input>要素のonChangeイベントでhandleChangeメソッドが呼び出され、入力値がステートに更新されます。その後、更新されたステートが表示される<p>要素に反映されます。

これらの概念を身につけることで、Reactアプリケーション内でユーザーの入力やイベントに対応することが可能となります。次に、条件付きレンダリングなど、Reactの応用的な機能に進んでいきましょう。

条件付きレンダリング

[編集]

Reactでは、特定の条件が満たされたときにコンポーネントの表示を切り替える「条件付きレンダリング」が一般的です。これにより、ユーザーの操作やデータの状態に基づいて、動的なUIを実現することができます。

条件文を使用した表示の切り替え

[編集]

最も基本的な形の条件付きレンダリングは、JavaScriptの条件演算子(三項演算子)を使用する方法です。

import React from 'react';

class Greeting extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isLoggedIn: false };
  }

  render() {
    return (
      <div>
        {this.state.isLoggedIn ? (
          <p>Welcome back, User!</p>
        ) : (
          <p>Please log in.</p>
        )}
      </div>
    );
  }
}

この例では、isLoggedInというステートの値によって表示されるメッセージが切り替わります。条件が真の場合は「Welcome back, User!」が表示され、偽の場合は「Please log in.」が表示されます。

ロジックに基づくコンポーネントの表示

[編集]

複雑な条件やロジックに基づいてコンポーネントを表示する場合は、条件に合致するコンポーネントを変数に格納し、それをJSX内で使用する方法があります。

import React from 'react';

class TemperatureDisplay extends React.Component {
  constructor(props) {
    super(props);
    this.state = { temperature: 25 };
  }

  render() {
    const { temperature } = this.state;

    let message;
    if (temperature > 30) {
      message = <p>It's too hot!</p>;
    } else if (temperature < 10) {
      message = <p>It's too cold!</p>;
    } else {
      message = <p>The temperature is just right.</p>;
    }

    return (
      <div>
        <p>Current Temperature: {temperature}°C</p>
        {message}
      </div>
    );
  }
}

この例では、温度に基づいて表示するメッセージを動的に切り替えています。message変数に条件に合致するJSXを代入し、それをレンダリングしています。

条件付きレンダリングを上手に利用することで、異なる状態やデータに対応した動的なUIを構築することができます。次に、Reactアプリケーションの最適化やコンポーネント間のデータ伝達について学びましょう。

リストとキー

[編集]

Reactにおいて、リストを効果的に表示するためには、配列を使って動的に要素を生成し、それぞれにユニークなキーを付与することが重要です。これにより、Reactが正確にどの要素が変更されたかを判断し、最適な再レンダリングを実現できます。

配列を使ったリストの表示

[編集]

配列を使ってリストを表示する際には、map関数を活用します。以下は、単純なリストの例です。

import React from 'react';

class TodoList extends React.Component {
  constructor(props) {
    super(props);
    this.state = { todos: ['Task 1', 'Task 2', 'Task 3'] };
  }

  render() {
    return (
      <ul>
        {this.state.todos.map((todo, index) => (
          <li key={index}>{todo}</li>
        ))}
      </ul>
    );
  }
}

この例では、todosという配列内の各要素をmap関数で取り出し、それぞれの要素にインデックスをキーとして付与しています。ただし、この方法は一意なキーを保証できないため、もし可能であれば一意なIDを使用する方が良いでしょう。

ユニークなキーの付与

[編集]

一意なキーを持つことはReactでのリスト表示において重要です。これによりReactは、要素の変更や削除を正確にトラックできます。

import React from 'react';

class TodoList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      todos: [
        { id: 1, text: 'Task 1' },
        { id: 2, text: 'Task 2' },
        { id: 3, text: 'Task 3' },
      ],
    };
  }

  render() {
    return (
      <ul>
        {this.state.todos.map((todo) => (
          <li key={todo.id}>{todo.text}</li>
        ))}
      </ul>
    );
  }
}

このように、リストの各要素には一意なIDを持たせることで、Reactが要素の追加、変更、削除などを正確に処理できます。

リストとキーを理解することで、動的で柔軟なUIを構築する際において、Reactが効果的に動作するようになります。次に、フォームの作成と入力処理とコントロールされたコンポーネントについて学んでいきましょう。

フォームと入力処理

[編集]

Reactにおいて、フォームの作成と入力処理は一般的なタスクです。Reactを使用することで、フォームの状態を簡単に管理し、ユーザーの入力に対して動的に反応するUIを構築できます。

フォームの作成と入力処理

[編集]

Reactでは、通常のHTMLフォームと同様に、<form>要素を使用します。フォーム内の入力要素は、通常のHTMLと同様に、<input><select><textarea>などを使用します。以下は、シンプルなフォームの例です。

import React from 'react';

class MyForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = { inputValue: '' };
  }

  handleChange(event) {
    this.setState({ inputValue: event.target.value });
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.inputValue);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={(event) => this.handleSubmit(event)}>
        <label>
          Name:
          <input
            type="text"
            value={this.state.inputValue}
            onChange={(event) => this.handleChange(event)}
          />
        </label>
        <button type="submit">Submit</button>
      </form>
    );
  }
}

この例では、<input>の値をinputValueというステートに保存し、onChangeイベントでその値を更新しています。また、<form>onSubmitイベントでフォームの送信を処理しています。

コントロールされたコンポーネント

[編集]

Reactでは、フォーム要素の値をReactのステートで管理することを「コントロールされたコンポーネント」と呼びます。これにより、フォーム要素とReactのステートが同期し、リアルタイムにユーザーの入力に対応できます。

import React, { useState } from 'react';

function ControlledForm() {
  const [inputValue, setInputValue] = useState('');

  const handleChange = (event) => {
    setInputValue(event.target.value);
  };

  const handleSubmit = (event) => {
    alert('A name was submitted: ' + inputValue);
    event.preventDefault();
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" value={inputValue} onChange={handleChange} />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
}

関数コンポーネントではuseStateフックを使用してステートを管理します。valueonChangeを使用して、入力要素とステートを連動させています。

フォームと入力処理の理解により、Reactを使った動的なユーザーインターフェースの構築がより容易になります。次に、ReactのライフサイクルやHooksの詳細などを学んでいきましょう。

コンポーネントのライフサイクル

[編集]

Reactコンポーネントは、マウント(Mounting)、アンマウント(Unmounting)、更新(Updating)の3つのフェーズでライフサイクルが管理されています。それぞれのフェーズにはライフサイクルメソッドが存在し、これらを利用することで特定のタイミングでの処理を実行できます。

マウント、アンマウント、更新のフェーズ

[編集]
  1. マウント(Mounting):
    • コンポーネントがDOMに挿入される最初の瞬間。
    • constructorrendercomponentDidMountなどが主に利用される。
  2. アンマウント(Unmounting):
    • コンポーネントがDOMから削除される瞬間。
    • componentWillUnmountなどが利用され、クリーンアップやリソース解放が行われる。
  3. 更新(Updating):
    • コンポーネントが再描画される瞬間。
    • shouldComponentUpdaterendercomponentDidUpdateなどが主に利用され、条件に応じた更新やサイドエフェクトの処理が行われる。

ライフサイクルメソッドの使用

[編集]

以下に代表的なライフサイクルメソッドを示します。

  1. constructor(props)
    • コンポーネントの初期化を行うメソッド。
    • コンストラクタ内でthis.stateを設定することができる。
  2. render()
    • コンポーネントを描画するメソッド。
    • render内ではステートとプロパティにアクセスし、JSXを返す。
  3. componentDidMount()
    • コンポーネントがDOMにマウントされた後に呼ばれるメソッド。
    • APIリクエストの発行や外部ライブラリの初期化など、マウント後の処理に利用される。
  4. componentWillUnmount()
    • コンポーネントがDOMからアンマウントされる前に呼ばれるメソッド。
    • イベントリスナーの解除やリソースの解放など、アンマウント前のクリーンアップに利用される。
  5. shouldComponentUpdate(nextProps, nextState)
    • コンポーネントが再描画される前に呼ばれるメソッド。
    • 返り値がtrueの場合、再描画が行われる。パフォーマンスの最適化に利用される。
  6. componentDidUpdate(prevProps, prevState)
    • コンポーネントが再描画された後に呼ばれるメソッド。
    • 更新後のDOMにアクセスするための処理に利用される。

これらのメソッドを活用することで、コンポーネントのライフサイクルの各ステージで必要な処理を行うことができます。React Hooksを使った関数コンポーネントにおいては、useEffectなどのフックがこれらの機能を提供します。

React Hooksの導入

[編集]

React Hooksは、React v16.8以降で導入された機能であり、関数コンポーネントにおいて状態やライフサイクルメソッドなどの機能を利用できるようにします。主なHooksとしてはuseStateuseEffectなどがあります。また、これらの基本的なHooksを組み合わせて独自のHooksを作成することもできます。

useState、useEffectの基本

[編集]

useState

[編集]

useState Hookは、関数コンポーネント内で状態を管理するために使用されます。通常のクラスコンポーネントにおけるthis.stateと同様の機能を提供します。

import React, { useState } from 'react';

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

useEffect

[編集]

useEffect Hookは、コンポーネントがマウント、アンマウント、または更新される際に副作用を実行するために使用されます。クラスコンポーネントにおけるライフサイクルメソッド(componentDidMountcomponentDidUpdatecomponentWillUnmount)に相当します。

import React, { useEffect, useState } from 'react';

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

  useEffect(() => {
    // マウント時に実行される処理
    fetchData();

    // アンマウント時のクリーンアップ
    return () => {
      // クリーンアップ処理
    };
  }, []); // 空の依存リストはコンポーネントのマウントとアンマウント時にのみ実行

  return <div>{data ? data : 'Loading...'}</div>;
}

カスタムフックの作成

[編集]

カスタムフックは、Hooksを組み合わせて独自のロジックを抽象化したものです。カスタムフックの名前は通常useで始まり、複数のHookを組み合わせて再利用性の高い機能を作成することができます。

import { useState, useEffect } from 'react';

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

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        const result = await response.json();
        setData(result);
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };

    fetchData();
  }, [url]);

  return data;
}

// 他のコンポーネントで使用
function ExampleComponent() {
  const data = useFetch('https://api.example.com/data');

  return <div>{data ? data : 'Loading...'}</div>;
}

このように、カスタムフックを使うことで特定の機能を抽象化し、複数のコンポーネントで再利用できるようになります。React Hooksをうまく活用することで、コンポーネントのロジックをより明確にし、コードの再利用性を向上させることができます。

ルーティングとReact Router

[編集]

Reactアプリケーションにおいて、異なるページやビューを表示するためには、ルーティングの実装が必要です。React Routerは、Reactアプリケーションのための人気のあるルーティングライブラリであり、ページ遷移や動的なルーティングを容易に実現できます。

React Routerの導入

[編集]

まず最初に、React Routerをプロジェクトに導入します。以下のコマンドを使用して、react-router-domをインストールします。

npm install react-router-dom

ページ遷移の実装

[編集]

React Routerを使用して、複数のページやビューを実現するためには、BrowserRouterRouteコンポーネントを使用します。

// App.js
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';

const Home = () => <div>Home Page</div>;
const About = () => <div>About Page</div>;

function App() {
  return (
    <Router>
      <nav>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
        </ul>
      </nav>

      <Route path="/" exact component={Home} />
      <Route path="/about" component={About} />
    </Router>
  );
}

export default App;

上記の例では、BrowserRouterを使用して//aboutのパスに対応するコンポーネント(HomeAbout)を表示しています。Linkコンポーネントを使用することで、ページ間のリンクを簡単に作成できます。

動的なルーティング

[編集]

React Routerを使用することで、動的なルーティングも実現できます。例えば、ユーザーのIDに基づいて個別のユーザーページを表示する場合などです。

// App.js
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';

const User = ({ match }) => (
  <div>
    User ID: {match.params.id}
  </div>
);

function App() {
  return (
    <Router>
      <nav>
        <ul>
          <li>
            <Link to="/user/1">User 1</Link>
          </li>
          <li>
            <Link to="/user/2">User 2</Link>
          </li>
        </ul>
      </nav>

      <Route path="/user/:id" component={User} />
    </Router>
  );
}

export default App;

この例では、:idという動的なパラメータを使用して、/user/1/user/2などのパスに対応するユーザーページを表示しています。match.params.idを通じて、動的なパラメータの値にアクセスできます。

React Routerを使用することで、シンプルかつ効果的にReactアプリケーション内でのルーティングを実現できます。

状態管理とContext API

[編集]

Reactアプリケーションでは、グローバルな状態を管理する必要がある場面があります。Context APIは、Reactコンポーネントツリー全体で共有されるグローバルな状態を簡単に管理するための手段を提供します。

グローバルなステートの管理

[編集]

Context APIを使用することで、Reduxなどの状態管理ライブラリを導入せずに、アプリケーション全体で共有される状態を簡単に管理できます。以下は、基本的なContextの使用例です。

// DataContext.js
import React, { createContext, useState, useContext } from 'react';

const DataContext = createContext();

export const DataProvider = ({ children }) => {
  const [data, setData] = useState('Initial Data');

  const updateData = (newData) => {
    setData(newData);
  };

  return (
    <DataContext.Provider value={{ data, updateData }}>
      {children}
    </DataContext.Provider>
  );
};

export const useData = () => {
  const context = useContext(DataContext);
  if (!context) {
    throw new Error('useData must be used within a DataProvider');
  }
  return context;
};

この例では、DataContextを作成し、DataProviderでグローバルなステートとその更新関数を提供しています。useDataカスタムフックを使用することで、どのコンポーネントでもグローバルなステートにアクセスできます。

Contextを使用したデータの共有

[編集]

アプリケーション内の異なる部分で同じデータを共有する場合、Context APIを活用することが重要です。以下は、前述のDataProviderを使用して、異なるコンポーネントでデータを共有する例です。

App.js
// App.js
import React from 'react';
import { DataProvider } from './DataContext';
import ComponentA from './ComponentA';
import ComponentB from './ComponentB';

function App() {
  return (
    <DataProvider>
      <div>
        <h1>App Component</h1>
        <ComponentA />
        <ComponentB />
      </div>
    </DataProvider>
  );
}

export default App;
ComponentA.js
// ComponentA.js
import React from 'react';
import { useData } from './DataContext';

const ComponentA = () => {
  const { data, updateData } = useData();

  return (
    <div>
      <h2>Component A</h2>
      <p>Data from Context: {data}</p>
      <button onClick={() => updateData('Updated Data from A')}>Update Data</button>
    </div>
  );
};

export default ComponentA;
ComponentB.js
// ComponentB.js
import React from 'react';
import { useData } from './DataContext';

const ComponentB = () => {
  const { data } = useData();

  return (
    <div>
      <h2>Component B</h2>
      <p>Data from Context: {data}</p>
    </div>
  );
};

export default ComponentB;

DataProviderで提供されたグローバルなステートを、useDataカスタムフックを介してComponentAComponentBで共有しています。これにより、どちらのコンポーネントでも同じデータを読み書きすることができます。

Context APIは、簡潔ながらも効果的なグローバルな状態管理の手段を提供し、Reactアプリケーションの複雑さを低減させます。

最終プロジェクトの構築

[編集]

これまでの知識を活かして、Reactアプリケーションを開発してみましょう。

この最終プロジェクトでは、以下の要素を含めたシンプルなタスク管理アプリケーションを構築します。

  1. タスクの追加、削除、完了/未完了の切り替え機能
  2. グローバルな状態管理としてContext APIの利用
  3. ルーティングにReact Routerの導入
  4. コンポーネントの再利用
  5. スタイリングのためにCSSやライブラリの利用

以下は、プロジェクトを進めるための基本的な構成です。この構成をベースにしながら、アプリケーションをカスタマイズしていってください。

プロジェクトのセットアップ

[編集]

まず、新しいReactプロジェクトを作成します。

npx create-react-app task-manager
cd task-manager

必要なパッケージをインストールします。

npm install react-router-dom

プロジェクトのファイル構成

task-manager
├── src
│   ├── components
│   │   ├── TaskList.js
│   │   └── TaskForm.js
│   ├── context
│   │   └── TaskContext.js
│   ├── pages
│   │   ├── Home.js
│   │   └── About.js
│   ├── App.js
│   ├── index.js
│   └── styles.css
└── package.json

コンポーネントの作成

[編集]
TaskList.js
// TaskList.js
import React from 'react';
import { useTask } from '../context/TaskContext';

const TaskList = () => {
  const { tasks, toggleTask, deleteTask } = useTask();

  return (
    <ul>
      {tasks.map((task) => (
        <li key={task.id}>
          <input
            type="checkbox"
            checked={task.completed}
            onChange={() => toggleTask(task.id)}
          />
          <span className={task.completed ? 'completed' : ''}>{task.text}</span>
          <button onClick={() => deleteTask(task.id)}>Delete</button>
        </li>
      ))}
    </ul>
  );
};

export default TaskList;
TaskForm.js
// TaskForm.js
import React, { useState } from 'react';
import { useTask } from '../context/TaskContext';

const TaskForm = () => {
  const { addTask } = useTask();
  const [text, setText] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (text.trim() !== '') {
      addTask(text);
      setText('');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Add a new task"
        value={text}
        onChange={(e) => setText(e.target.value)}
      />
      <button type="submit">Add Task</button>
    </form>
  );
};

export default TaskForm;

Context APIの設定

[編集]
TaskContext.js
// TaskContext.js
import React, { createContext, useContext, useState } from 'react';

const TaskContext = createContext();

export const TaskProvider = ({ children }) => {
  const [tasks, setTasks] = useState([]);

  const addTask = (text) => {
    setTasks([...tasks, { id: tasks.length + 1, text, completed: false }]);
  };

  const deleteTask = (taskId) => {
    setTasks(tasks.filter((task) => task.id !== taskId));
  };

  const toggleTask = (taskId) => {
    setTasks(
      tasks.map((task) =>
        task.id === taskId ? { ...task, completed: !task.completed } : task
      )
    );
  };

  return (
    <TaskContext.Provider value={{ tasks, addTask, deleteTask, toggleTask }}>
      {children}
    </TaskContext.Provider>
  );
};

export const useTask = () => {
  const context = useContext(TaskContext);
  if (!context) {
    throw new Error('useTask must be used within a TaskProvider');
  }
  return context;
};

ページの作成

[編集]
Home.js
// Home.js
import React from 'react';
import TaskList from '../components/TaskList';
import TaskForm from '../components/TaskForm';

const Home = () => {
  return (
    <div>
      <h1>Task Manager</h1>
      <TaskForm />
      <TaskList />
    </div>
  );
};

export default Home;
About.js
// About.js
import React from 'react';

const About = () => {
  return (
    <div>
      <h1>About Page</h1>
      <p>This is a simple task manager application built with React.</p>
    </div>
  );
};

export default About;

ルーティングの設定

[編集]
App.js
// App.js
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import { TaskProvider } from './context/TaskContext';

function App() {
  return (
    <Router>
      <TaskProvider>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
          </ul>
        </nav>

        <Route path="/" exact component={Home} />
        <Route path="/about" component={About} />
      </TaskProvider>
    </Router>
  );
}

export default App;

スタイリングの追加

[編集]
styles.css
/* styles.css */
body {
  font-family: 'Arial', sans-serif;
}

h1 {
  color: #333;
}

form {
  margin-bottom: 20px;
}

ul {
  list-style: none;
  padding: 0;
}

li {
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}

.completed {
  text-decoration: line-through;
  color: #999;
}

button {
  margin-left: 10px;
  cursor: pointer;
}

以上で、シンプルなタスク管理アプリケーションが完成しました。このプロジェクトをベースにして、機能の拡張やデザインのカスタマイズを行いながら、Reactの様々な機能やライブラリを実践してみてください。

デプロイと公開

[編集]

Reactアプリケーションを開発したら、それをビルドし、デプロイして公開することが重要です。以下では、Reactアプリケーションをビルドし、一般的なデプロイ方法を紹介します。

アプリケーションのビルド

[編集]

Reactアプリケーションをビルドすると、最適化された静的なファイルが生成され、これをサーバーにデプロイして公開することができます。

ビルドは以下のコマンドで行います。

npm run build

このコマンドを実行すると、buildディレクトリが生成され、その中にビルドされたファイルが格納されます。

アプリケーションのデプロイ

[編集]

デプロイの方法はいくつかありますが、ここでは簡単な2つの方法を紹介します。

GitHub Pagesを利用する

[編集]
  1. GitHub レポジトリの作成: GitHubに新しいレポジトリを作成します。
  2. コードをプッシュ: ローカルでビルドしたコードをGitHubレポジトリにプッシュします。
    git remote add origin <GitHub レポジトリのURL>
    git add .
    git commit -m "ビルドしたコードを追加"
    git push -u origin master
    
  3. GitHub Pagesの有効化: GitHubのレポジトリの設定から、"Pages"セクションに移動し、Sourcegh-pagesmasterブランチに設定します。
  4. 公開されたURLの確認: デプロイされたアプリケーションは、GitHub PagesのURLで公開されます。例: https://username.github.io/repository-name

Netlifyを利用する

[編集]
  1. Netlify アカウントの作成: Netlifyでアカウントを作成します。
  2. 新しいサイトを作成: Netlifyのダッシュボードから新しいサイトを作成します。GitHubを連携させると、リポジトリを選択してデプロイできます。
  3. ビルド設定: デプロイされる前に、ビルドコマンドとディレクトリを設定する必要があります。通常は、以下の設定を使用します。
    • Build command: npm run build
    • Publish directory: build
  4. デプロイ: 設定が完了したら、手動でデプロイするか、GitHubと連携して自動デプロイを行います。
  5. 公開されたURLの確認: デプロイされたアプリケーションは、Netlifyの提供するURLで公開されます。
    例: https://yoursite.netlify.app

注意事項

[編集]
  • ビルドしたコードは、デプロイする環境によって異なる挙動を示すことがあります。テストが不可欠です。
  • APIキーなどの秘密情報は、環境変数を用いてセキュアに管理することが重要です。
  • デプロイしたアプリケーションが正しく動作するか、定期的に確認しましょう。

これで、Reactアプリケーションをビルドしてデプロイし、公開する基本的な手順を学びました。デプロイ先によって手順が異なるため、選択したプラットフォームのドキュメントも確認することをお勧めします。

用語集

[編集]
API (Application Programming Interface)
アプリケーションとプログラム間の相互作用を可能にするインターフェース。ReactやReact Nativeが提供するAPIは、開発者がライブラリやフレームワークと対話する手段です。
Component (コンポーネント)
UIを構築するための再利用可能な部品。Reactアプリケーションはコンポーネントベースのアーキテクチャで構築され、UIを独立した部品に分割します。
Context API
グローバルな状態を管理するためのReactのAPI。コンポーネントツリー全体でデータを渡すために使用され、プロバイダーとコンシューマーの役割を果たします。
Higher-Order Component (HOC)
コンポーネントをラップして新しい機能を追加するための高階関数。コンポーネントのロジックを再利用し、コードの共有を容易にします。
Hooks
React 16.8以降で導入された機能で、関数コンポーネント内で状態やライフサイクルの機能を利用できるようにするもの。代表的なものにはuseStateuseEffectがあります。
JSX (JavaScript XML)
JavaScriptの構文拡張で、Reactコンポーネントの見た目を記述するために使用される。HTMLライクな構文で、JavaScript内でXML構造を表現できる。
React
Meta(以前のFacebook)が開発したJavaScriptライブラリで、ユーザーインターフェースを構築するために使用される。Reactは、コンポーネントベースのアーキテクチャと仮想DOMを提供しています。
Redux
Reactアプリケーションの状態管理を行うためのJavaScriptライブラリ。単一のストアでアプリケーション全体の状態を管理します。
Reducer
Reduxで状態の変更を処理する純粋な関数。アクションに基づいて新しい状態を生成します。
State (ステート)
Reactコンポーネント内で管理される状態のこと。useStateフックを使用してコンポーネント内でステートを宣言できます。
Styled Components
Reactアプリケーション内でスタイルを付けるためのライブラリ。JavaScript内にスタイルを記述し、コンポーネントに直接適用できる。
Virtual DOM
Reactが効率的なUI更新を行うために使用する仮想のDOM。変更があった部分のみを実際のDOMに反映させ、パフォーマンスを向上させる。
WebPack
モジュールバンドラで、Reactプロジェクトのビルドやバンドルに使用される。JavaScript、CSS、画像などをバンドルし、効率的に管理する。

まとめ

[編集]

React.jsとTypeScriptの基本的な概念の再確認

[編集]

React.jsとTypeScriptを使用して、モダンなフロントエンド開発を行うための基本的な概念について学びました。以下は、このチュートリアルで取り上げた主要なトピックです。

  1. React.jsの基礎:
    • JSXの導入と使用
    • コンポーネントの作成と再利用
    • プロパティとステートの管理
    • イベントハンドリングと条件付きレンダリング
    • リストとキーの重要性
  2. React Hooks:
    • useStateuseEffectの基本的な使用法
    • カスタムフックの作成
    • 関数コンポーネント内での状態管理
  3. React Router:
    • ルーティングの基本
    • 動的なルーティングの実装
  4. Context API:
    • グローバルな状態の管理
    • createContextuseContextuseReducerの活用
  5. TypeScriptとの統合:
    • TypeScriptの導入と基本的な型の付与
    • TypeScriptを使用したReactコンポーネントの記述
  6. 最終プロジェクト:
    • タスク管理アプリケーションの構築
    • コンポーネント、ルーティング、状態管理の統合

今後の学習のためのリソース

[編集]

このチュートリアルを通じてReact.jsとTypeScriptの基本を学びましたが、これはまだ始まりに過ぎません。以下は、これから学習を深めるためのリソースです。

  1. React 公式ドキュメント:
    • React 公式ドキュメント( https://react.dev/ )は常に最新で詳細な情報が提供されています。新しい機能やアップデートに追従するために、定期的にチェックしましょう。
  2. TypeScript 公式ハンドブック:
  3. React Router 公式ドキュメント:
    • React Router 公式ドキュメント( https://reactrouter.com/en/main )で、Reactアプリケーションのナビゲーションとルーティングに関する詳細な情報を入手できます。
  4. Netlify Documentation:
    • Netlify Documentation( https://docs.netlify.com/ )で、Netlifyを使用したアプリケーションのデプロイとホスティングに関するガイドを確認できます。

React.jsとTypeScriptを組み合わせて使いこなすためには、実際のプロジェクトでの経験が最も効果的です。小さなプロジェクトから始めて、徐々に複雑なアプリケーションに挑戦してみましょう。学習の旅がさらなる成長とスキル向上につながります。成功を祈ります!

脚註

[編集]


参考資料

[編集]