React + Spring Boot 入門ガイド

はい、承知いたしました。ReactとSpring Bootを使ったWebアプリケーション開発の入門ガイド記事を、詳細な説明を含めて約5000語で記述します。


React + Spring Boot 入門ガイド:モダンなWebアプリケーション開発の第一歩

はじめに

Webアプリケーション開発の世界は常に進化しています。特に、ユーザーインターフェースの表現力と開発効率を高めるフロントエンド技術と、堅牢でスケーラブルなバックエンド技術の組み合わせは、現代のWeb開発の主流となっています。その中でも、フロントエンドの代表格であるReactと、Javaバックエンドの定番であるSpring Bootの組み合わせは、多くの企業で採用され、高い生産性と保守性を実現できる強力なスタックとして知られています。

本記事では、この「React + Spring Boot」スタックを使って、シンプルなWebアプリケーションを開発するプロセスを、環境構築から丁寧に解説します。フロントエンドをReactで、バックエンドをSpring Bootで構築し、両者を連携させて動作する基本的なCRUD(作成・読み取り・更新・削除)アプリケーションを通じて、それぞれの技術の基本と、連携方法を実践的に学びます。

この記事は、以下のような方を対象としています。

  • Javaの基本的な知識があり、Spring Bootを使ったWeb開発に興味がある方。
  • JavaScriptの基本的な知識があり、Reactを使ったフロントエンド開発に興味がある方。
  • フロントエンドとバックエンドを組み合わせたモダンなWebアプリケーション開発の全体像を学びたい方。
  • ただし、これらの技術に深く精通している必要はありません。入門レベルからステップアップしたい方を想定しています。

約5000語のボリュームで、各ステップの詳細な説明とコード例を含みます。このガイドを通して、あなたもReactとSpring Bootを使ったアプリケーション開発の第一歩を踏み出しましょう。

第1章 技術スタックの概要

開発を始める前に、今回使用する主要な技術であるReactとSpring Boot、そしてなぜこれらを組み合わせるのかについて理解を深めましょう。

1.1 Reactとは

Reactは、Facebook(現Meta)が開発したJavaScriptライブラリで、ユーザーインターフェース(UI)を構築するために使われます。「ライブラリ」であり、フレームワークではありません。これは、Webアプリケーション開発のUI部分に特化していることを意味します。

Reactの主な特徴:

  • コンポーネント指向: UIを「コンポーネント」と呼ばれる独立した再利用可能な部品に分割して開発します。これにより、コードの見通しが良くなり、保守性が向上します。
  • 仮想DOM (Virtual DOM): Reactは、実際のDOM(Document Object Model)の軽量なコピーである仮想DOMをメモリ上に保持します。UIに変更があった際、まず仮想DOM上で変更を反映し、実際のDOMとの差分を最小限に抑えて効率的に更新します。これにより、パフォーマンスの高いUI描画を実現します。
  • 宣言的UI: UIの状態を宣言的に記述します。「このデータがあるときはこのUIを表示する」というように、UIの状態と見た目を紐づけて記述するため、コードが予測しやすく、デバッグが容易になります。
  • 単方向データフロー: データは親コンポーネントから子コンポーネントへと一方向に流れます。これにより、アプリケーションの状態管理がシンプルになり、データの流れを追いやすくなります。
  • SPA (Single Page Application) 開発への適性: ページ遷移時に全体のHTMLを再読み込みするのではなく、JavaScriptを使って動的にコンテンツを書き換えるSPAの開発に非常に適しています。これにより、ユーザー体験の向上につながります。

ReactはUI開発に特化しているため、ルーティングや状態管理など、UI以外の機能については別途ライブラリを選択して組み合わせるのが一般的です。(例: React Router, Redux, Zustandなど)

1.2 Spring Bootとは

Spring Bootは、Java言語でWebアプリケーションやマイクロサービスを迅速に開発するためのフレームワークであるSpring Frameworkのサブプロジェクトです。「Boot」という名の通り、最小限の設定でSpringアプリケーションを「ブート(起動)」させることに焦点を当てています。

Spring Bootの主な特徴:

  • 設定より規約 (Convention over Configuration): 多くの設定をデフォルトで提供しており、開発者は最小限の設定で開発を開始できます。これにより、開発の初期段階での手間を大幅に削減できます。
  • スタンドアロンアプリケーション: TomcatやJettyといった組み込みのWebサーバーを含んでいるため、別途Webサーバーを用意することなく、単一のJARファイルとしてアプリケーションを実行できます。
  • 依存関係管理の簡素化: spring-boot-starter-* といったStarter POMs(Maven)やStarter Gradle Dependencies(Gradle)を使用することで、関連するライブラリの依存関係をまとめて簡単に管理できます。
  • 豊富な機能: Spring Frameworkが提供するDI (Dependency Injection)、AOP (Aspect-Oriented Programming)、トランザクション管理、セキュリティ、データアクセス(JPA, JDBCなど)といった強力な機能を容易に利用できます。
  • RESTful API開発への適性: アノテーションベースで簡単にRESTful APIを構築できます。

Spring Bootは、その手軽さと強力な機能から、バックエンド開発のデファクトスタンダードの一つとなっています。

1.3 なぜReactとSpring Bootを組み合わせるのか?

ReactとSpring Bootは、それぞれフロントエンドとバックエンドという異なる役割を担う技術ですが、これらを組み合わせることで、それぞれの強みを活かした効率的でスケーラブルなWebアプリケーションを構築できます。

  • 明確な役割分担: ReactがUIの表示とユーザー操作の処理を担当し、Spring Bootがビジネスロジック、データ永続化、API提供を担当します。これにより、開発チーム内でフロントエンドとバックエンドの開発を並行して進めやすくなります。
  • APIによる連携: フロントエンド(React)は、バックエンド(Spring Boot)が提供するRESTful APIを通じてデータとビジネスロジックにアクセスします。APIは両者間の明確な契約となり、疎結合なアーキテクチャを実現します。
  • スケーラビリティ: フロントエンドとバックエンドを独立してスケールさせることが可能です。例えば、APIへの負荷が高い場合はバックエンドのインスタンスを増やし、UIへのアクセスが多い場合はCDNを利用するなど、それぞれの特性に合わせて最適なスケーリング戦略を選択できます。
  • 技術選択の自由度: フロントエンドとバックエンドがAPIで分離されているため、将来的に片方の技術を別の技術に置き換えることも比較的容易です(例: ReactをVueやAngularに、Spring BootをNode.jsやPython+Djangoなどに)。
  • 開発効率: Spring Bootの迅速なAPI開発能力と、Reactのコンポーネントベースでの効率的なUI開発能力を組み合わせることで、開発全体の生産性を高めることができます。

このように、ReactとSpring Bootは、現代の分散型アーキテクチャに基づいたWebアプリケーション開発において、非常に相性の良い組み合わせと言えます。

第2章 開発環境の準備

React + Spring Bootアプリケーションを開発するためには、いくつかのソフトウェアをインストールする必要があります。

2.1 前提条件

  • Java Development Kit (JDK): Spring Bootアプリケーションを実行するにはJavaが必要です。最新のLTS(長期サポート)バージョンを推奨します(例: Java 11, Java 17, Java 21)。
  • Node.js と npm または Yarn: Reactアプリケーションの開発にはNode.jsが必要です。Node.jsをインストールすると、パッケージマネージャーであるnpm(Node Package Manager)も一緒にインストールされます。npmの代わりにYarnやpnpmを使用することもできます。
  • Maven または Gradle: Spring Bootプロジェクトの依存関係管理やビルドに使用します。Spring InitializrやIDEでプロジェクトを作成する際に自動的にダウンロード・設定されることが多いですが、コマンドラインから操作する場合は単体でインストールが必要になることもあります。
  • 統合開発環境 (IDE): 開発効率を大幅に向上させるIDEの利用を強く推奨します。
    • IntelliJ IDEA: Spring開発において非常に強力なサポートを提供します(有償のUltimate版が最も機能が豊富ですが、無償のCommunity版でも基本的な開発は可能です)。
    • Visual Studio Code (VS Code): 軽量ながら豊富な拡張機能により様々な言語に対応できます。Java開発、React開発ともに優れた拡張機能があります。
    • Eclipse: Spring Tools Suite (STS) というSpring開発に特化したディストリビューションがあります。

2.2 各ツールのインストール

2.2.1 Java (JDK) のインストール

Oracle JDK、OpenJDK、Adoptium Temurinなど、様々なディストリビューションがあります。推奨は無償で利用できるOpenJDKベースのディストリビューション(例: Adoptium Temurin, Amazon Corretto, Microsoft Build of OpenJDKなど)です。

  • Windows:
    • Adoptium Temurinの公式サイトからインストーラーをダウンロードし、実行します。インストール中に「環境変数JAVA_HOMEを設定する」「Pathに追加する」といったオプションが表示されたら、有効にすることをお勧めします。
    • または、winget install Microsoft.OpenJDK.17 のようにパッケージマネージャーを使用します。
  • macOS:
    • Homebrewを使用するのが最も簡単です。ターミナルを開き、brew install --cask temurin のように実行します。(Homebrewがインストールされていない場合は、先にHomebrewをインストールしてください。)
  • Linux:
    • ディストリビューションのパッケージマネージャーを使用します。例えば、Debian/Ubuntu系なら sudo apt update && sudo apt install openjdk-17-jdk、Fedora/CentOS系なら sudo dnf install java-17-openjdk-devel のように実行します。

インストール後、ターミナルまたはコマンドプロンプトで java -version および javac -version を実行し、インストールしたバージョンが表示されるか確認してください。

2.2.2 Node.js のインストール

Node.jsの公式サイトから、お使いのOS用のインストーラーをダウンロードして実行するのが最も簡単です。推奨版(LTS版)をダウンロードしてください。

  • Windows / macOS: 公式サイトからインストーラーをダウンロードし、指示に従ってインストールします。インストール中に「npm package managerを含める」といったオプションはデフォルトで有効になっているはずです。
  • Linux: ディストリビューションのパッケージマネージャーを使用する方法と、NodeSourceなどのリポジトリを追加してインストールする方法があります。公式サイトのダウンロードページに各OS向けのインストール方法が記載されています。

インストール後、ターミナルまたはコマンドプロンプトで node -v および npm -v を実行し、バージョンが表示されるか確認してください。npmの代わりにYarnを使う場合は、npm install -g yarn でグローバルインストールしておくと便利です。本記事ではnpmを主に使用しますが、Yarnでもほとんど同じ操作です。

2.2.3 Maven / Gradle

IDEを使用する場合や、Spring Initializrでプロジェクトを生成する場合は、MavenまたはGradleのWrapper(プロジェクト内に含まれる実行スクリプト)が使用されるため、別途インストールする必要がないことが多いです。コマンドラインからグローバルにインストールして使用したい場合は、それぞれの公式サイトの手順に従ってください。

2.2.4 IDE の準備

選択したIDEをインストールし、Java開発およびJavaScript/TypeScript開発に必要なプラグイン/拡張機能をインストールします。

  • IntelliJ IDEA: 公式サイトからダウンロードしてインストールします。Spring Boot開発に必要な機能はUltimate版に標準装備されており、Community版でもJava開発およびJavaScript開発の基本的な機能は利用できます。
  • VS Code: 公式サイトからダウンロードしてインストールします。Java開発には「Extension Pack for Java」、Spring Boot開発には「Spring Boot Extension Pack」、React開発には「ESLint」「Prettier」「React Developer Tools (拡張機能ではないがブラウザに)」「TypeScript React Code Snippets」などの拡張機能をインストールすると便利です。
  • Eclipse: Spring Tools 4 for Eclipse を公式サイトからダウンロードします。

この記事では特定のIDEに依存しないように解説しますが、適宜IDEの機能に言及することがあります。

第3章 Spring Bootバックエンドの構築

まずはバックエンドであるSpring Bootアプリケーションを構築します。RESTful APIとして機能し、簡単なタスク管理機能(タスクの作成、一覧取得、更新、削除)を提供します。

3.1 Spring Bootプロジェクトの作成

Spring Initializr を利用するのが最も簡単です。ウェブブラウザで https://start.spring.io/ にアクセスしてください。または、IntelliJ IDEAなどのIDEに組み込まれているSpring Initializr機能を使用します。

ここではWebサイト版を使用して手順を説明します。以下の項目を設定します。

  • Project: Maven Project または Gradle Project (どちらでも構いませんが、本記事ではMavenを使用します)
  • Language: Java
  • Spring Boot: 安定版の最新バージョンを選択します
  • Project Metadata:
    • Group: 例: com.example
    • Artifact: 例: task-manager
    • Name: 例: task-manager (Artifactと同じで構いません)
    • Description: 例: Task Manager Backend with Spring Boot
    • Package name: 例: com.example.taskmanager (GroupとArtifactから自動生成されます)
    • Packaging: Jar (Warでも構いませんが、組み込みサーバーを使う場合はJarが一般的です)
    • Java: インストール済みのJDKのバージョンに合わせます(例: 17, 21など)
  • Dependencies: 必要な依存関係を追加します。「Add Dependencies」ボタンをクリックし、以下を検索して追加します。
    • Spring Web: RESTful APIの構築に必要です。
    • Spring Data JPA: データベースアクセス(O/Rマッパー)に必要です。
    • H2 Database: 開発やテスト用のインメモリデータベースです。別途データベースサーバーを用意する手間が省けます。
    • Lombok (任意): ボイラープレートコード(Getter/Setter, コンストラクタなど)を削減できます。非常に便利なので追加を推奨します。
    • Spring Boot DevTools (任意): 開発中のホットリロードなど、開発効率を向上させる機能を提供します。追加を推奨します。

設定後、「Generate」ボタンをクリックすると、ZIPファイルがダウンロードされます。このZIPファイルを展開し、お好みのIDEでプロジェクトを開きます。

プロジェクト構造は以下のようになっているはずです(Mavenの場合)。

task-manager/
├── .mvn/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/taskmanager/
│ │ │ └── TaskManagerApplication.java <- アプリケーションのエントリポイント
│ │ └── resources/
│ │ ├── application.properties <- 設定ファイル
│ │ ├── static/
│ │ └── templates/
│ └── test/
│ └── java/
│ └── com/example/taskmanager/
│ └── TaskManagerApplicationTests.java <- テストクラス
├── .gitignore
├── mvnw <- Maven Wrapper (Windows)
├── mvnw.cmd <- Maven Wrapper (Linux/macOS)
└── pom.xml <- Mavenの設定ファイル(依存関係など)

pom.xml ファイルには、Initializrで選択した依存関係が <dependencies> タグ内に記述されています。Lombokを追加した場合、IDEでLombokプラグインを有効にする必要があるかもしれません(IntelliJ IDEAなど)。

3.2 データモデル(Entity)の作成

タスクを表すデータモデルを作成します。src/main/java/com/example/taskmanager/ ディレクトリ内に Task.java ファイルを作成します。

“`java
package com.example.taskmanager;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;

@Entity // このクラスがJPAのエンティティであることを示す
@Data // Lombokによるgetter, setter, toString, equals, hashCodeの自動生成
@NoArgsConstructor // Lombokによる引数なしコンストラクタの自動生成
@AllArgsConstructor // Lombokによる全フィールド引数付きコンストラクタの自動生成
public class Task {

@Id // 主キーであることを示す
@GeneratedValue(strategy = GenerationType.IDENTITY) // 主キーがデータベースによって自動生成されることを示す
private Long id;

private String title; // タスクのタイトル
private boolean completed; // タスクが完了したかどうかの状態

// Lombokを使用しない場合は、以下のようなコンストラクタやgetter/setterを手動で記述する必要がある
/*
public Task() {}

public Task(String title, boolean completed) {
    this.title = title;
    this.completed = completed;
}

public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public boolean isCompleted() { return completed; }
public void setCompleted(boolean completed) { this.completed = completed; }

@Override
public String toString() { ... }
@Override
public boolean equals(Object o) { ... }
@Override
public int hashCode() { ... }
 */

}
“`

ここでは、タスクはid(主キー、自動生成)、title(文字列)、completed(真偽値)を持つシンプルな構造とします。jakarta.persistence パッケージはSpring Data JPAの依存関係に含まれるJPA(Java Persistence API)のものです。Lombokのアノテーションを使用すると、冗長なコードを削減できます。

3.3 リポジトリ(Repository)の作成

データベース操作を行うリポジトリインターフェースを作成します。src/main/java/com/example/taskmanager/ ディレクトリ内に TaskRepository.java ファイルを作成します。

“`java
package com.example.taskmanager;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

// JpaRepositoryを継承することで、基本的なCRUD操作(保存、検索、削除など)のメソッドが自動的に提供される
// は、エンティティクラスがTaskで、その主キーの型がLongであることを示す
@Repository // このインターフェースがSpringのリポジトリであることを示す(Spring Data JPAを使用する場合は必須ではないが多くの場合つける)
public interface TaskRepository extends JpaRepository {
// JpaRepositoryには以下のメソッドなどがデフォルトで含まれています。
// List findAll(); // 全件取得
// Optional findById(Long id); // IDで一件取得
// S save(S entity); // 保存(新規作成または更新)
// void deleteById(Long id); // IDで削除
// その他、命名規約に従ったメソッド(例: findByCompleted(boolean completed))を追加することも可能
}
“`

Spring Data JPAのJpaRepositoryを継承するだけで、Spring Bootが実行時にこのインターフェースの実装を自動生成し、データベースとの連携を可能にします。これで、独自のSQLやJDBCコードを書くことなく、オブジェクト指向的にデータベース操作を行えます。

3.4 コントローラー(Controller)の作成

フロントエンドからのリクエストを受け付け、処理を行い、レスポンスを返すコントローラーを作成します。RESTful APIとして /api/tasks エンドポイントを提供します。src/main/java/com/example/taskmanager/ ディレクトリ内に TaskController.java ファイルを作成します。

“`java
package com.example.taskmanager;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController // このクラスがRESTコントローラーであることを示す(@Controller + @ResponseBody)
@RequestMapping(“/api/tasks”) // このコントローラー内の全てのエンドポイントのベースパスを設定
@CrossOrigin(origins = “http://localhost:3000”) // フロントエンドからのクロスオリジンリクエストを許可
public class TaskController {

@Autowired // Springによる依存性注入(Dependency Injection)
private TaskRepository taskRepository; // TaskRepositoryの実装クラスが自動的にここに注入される

// GET /api/tasks
// 全てのタスクを取得
@GetMapping
public List<Task> getAllTasks() {
    // taskRepository.findAll() は JpaRepository が提供するメソッド
    return taskRepository.findAll();
}

// GET /api/tasks/{id}
// 指定されたIDのタスクを取得
@GetMapping("/{id}")
public ResponseEntity<Task> getTaskById(@PathVariable Long id) {
    // taskRepository.findById(id) は Optional<Task> を返す
    Optional<Task> task = taskRepository.findById(id);
    // タスクが見つかった場合はOK (200) と共にタスクを返し、見つからない場合はNot Found (404) を返す
    return task.map(ResponseEntity::ok) // taskが存在する場合
               .orElseGet(() -> ResponseEntity.notFound().build()); // taskが存在しない場合
}

// POST /api/tasks
// 新しいタスクを作成
@PostMapping
// @RequestBody は、リクエストボディのJSONをTaskオブジェクトに自動的にマッピングする
// @ResponseStatus(HttpStatus.CREATED) は、成功した場合のHTTPステータスコードを201 Createdに設定
@ResponseStatus(HttpStatus.CREATED)
public Task createTask(@RequestBody Task task) {
    // taskRepository.save(task) は JpaRepository が提供するメソッド
    // 新規作成の場合は、データベースによって生成されたIDが設定されたTaskオブジェクトが返される
    return taskRepository.save(task);
}

// PUT /api/tasks/{id}
// 指定されたIDのタスクを更新
@PutMapping("/{id}")
public ResponseEntity<Task> updateTask(@PathVariable Long id, @RequestBody Task taskDetails) {
    // 更新対象のタスクをIDで検索
    Optional<Task> task = taskRepository.findById(id);

    // タスクが見つかった場合
    if (task.isPresent()) {
        Task existingTask = task.get();
        // リクエストボディから受け取ったデータで既存のタスクの情報を更新
        existingTask.setTitle(taskDetails.getTitle());
        existingTask.setCompleted(taskDetails.isCompleted());

        // 更新されたタスクを保存(IDが存在するため、更新として扱われる)
        Task updatedTask = taskRepository.save(existingTask);
        // OK (200) と共に更新されたタスクを返す
        return ResponseEntity.ok(updatedTask);
    } else {
        // タスクが見つからなかった場合はNot Found (404) を返す
        return ResponseEntity.notFound().build();
    }
}

// DELETE /api/tasks/{id}
// 指定されたIDのタスクを削除
@DeleteMapping("/{id}")
// @ResponseStatus(HttpStatus.NO_CONTENT) は、成功した場合のHTTPステータスコードを204 No Contentに設定
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteTask(@PathVariable Long id) {
    // taskRepository.deleteById(id) は JpaRepository が提供するメソッド
    // IDが存在しない場合でも例外は発生しない(デフォルト設定の場合)
    taskRepository.deleteById(id);
}

}
“`

各メソッドは、対応するHTTPメソッド(@GetMapping, @PostMapping, @PutMapping, @DeleteMapping)とURLパス(@RequestMapping, @PathVariable)にマッピングされています。@RequestBody は、リクエストボディ(通常はJSON形式)をJavaオブジェクトに変換するために使用されます。ResponseEntity を使用すると、HTTPステータスコードやヘッダーなどをより細かく制御できます。

@CrossOrigin(origins = "http://localhost:3000") アノテーションは重要です。開発中、Spring Bootバックエンドはデフォルトで8080ポート、Reactフロントエンドはデフォルトで3000ポートで実行されます。異なるオリジン(ドメイン、ポート、プロトコル)からのリクエストは、ブラウザのセキュリティ機能であるCORS(Cross-Origin Resource Sharing)によって制限されます。このアノテーションにより、Reactアプリケーションが実行される http://localhost:3000 からのAPIリクエストを許可します。本番環境では、デプロイ方法に応じてこの設定を調整する必要があります。

3.5 H2 Database の設定

開発/テスト用のインメモリデータベースH2を使用するための設定を src/main/resources/application.properties ファイルに記述します。

“`properties

H2 Database Settings

spring.datasource.url=jdbc:h2:mem:taskdb # インメモリデータベース名
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password

H2 Console Settings (ブラウザからH2データベースの中身を確認できるWebコンソール)

spring.h2.console.enabled=true # コンソールを有効化
spring.h2.console.path=/h2-console # コンソールのURLパス

JPA Settings

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

ddl-auto:

create-drop: アプリケーション起動時にスキーマを作成し、終了時に削除する(開発/テスト向け)

create: アプリケーション起動時にスキーマを作成する(既に存在する場合はエラー)

update: エンティティの変更に合わせてスキーマを更新する(変更によってはデータ損失の可能性あり)

validate: スキーマを検証する

none: 何もしない

spring.jpa.hibernate.ddl-auto=create-drop # 開発中はcreate-dropが便利
spring.jpa.show-sql=true # 実行されるSQLをコンソールに出力
spring.jpa.properties.hibernate.format_sql=true # 出力されるSQLを整形
“`

これらの設定により、アプリケーション起動時に taskdb という名前のインメモリH2データベースが作成され、Task エンティティに基づいてテーブルが自動的に作成されます(ddl-auto=create-drop の設定による)。また、http://localhost:8080/h2-console にアクセスすると、ブラウザからデータベースの内容を確認できるH2コンソールが利用可能になります。コンソールへの接続設定はJDBC URLに jdbc:h2:mem:taskdb、ユーザー名 sa、パスワード password を入力します。

3.6 アプリケーションの実行とAPIテスト

Spring Bootアプリケーションを実行します。IDEからTaskManagerApplication.javamainメソッドを実行するか、プロジェクトのルートディレクトリでコマンドラインから以下のコマンドを実行します。

“`bash

Maven Wrapper を使用する場合

./mvnw spring-boot:run

Maven をグローバルにインストールしている場合

mvn spring-boot:run

“`

アプリケーションが起動すると、ログにH2コンソールへのURL(例: H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:taskdb')や、Tomcatが起動したポート(デフォルトは8080)が表示されます。

APIのテスト:

cURL、Postman、Insomniaなどのツールを使用して、作成したAPIエンドポイントをテストできます。

  1. タスク作成 (POST)

    • URL: http://localhost:8080/api/tasks
    • Method: POST
    • Headers: Content-Type: application/json
    • Body (Raw JSON):
      json
      {
      "title": "牛乳を買う",
      "completed": false
      }
    • レスポンス: ステータスコード 201 Created, 作成されたタスクのJSON(IDが付与されている)
  2. 別のタスク作成 (POST)

    • URL: http://localhost:8080/api/tasks
    • Method: POST
    • Headers: Content-Type: application/json
    • Body (Raw JSON):
      json
      {
      "title": "洗濯をする",
      "completed": true
      }
    • レスポンス: ステータスコード 201 Created
  3. 全タスク取得 (GET)

    • URL: http://localhost:8080/api/tasks
    • Method: GET
    • レスポンス: ステータスコード 200 OK, タスクのリストを示すJSON配列
  4. 特定のタスク取得 (GET – ID=1)

    • URL: http://localhost:8080/api/tasks/1
    • Method: GET
    • レスポンス: ステータスコード 200 OK, ID=1のタスクを示すJSON
  5. タスク更新 (PUT – ID=1を完了にする)

    • URL: http://localhost:8080/api/tasks/1
    • Method: PUT
    • Headers: Content-Type: application/json
    • Body (Raw JSON):
      json
      {
      "id": 1, // IDは含めても含まなくても良いが、パスパラメータのIDが優先される
      "title": "牛乳を買う",
      "completed": true
      }
    • レスポンス: ステータスコード 200 OK, 更新されたタスクのJSON
  6. タスク削除 (DELETE – ID=2)

    • URL: http://localhost:8080/api/tasks/2
    • Method: DELETE
    • レスポンス: ステータスコード 204 No Content

これらのテストが成功すれば、バックエンドAPIは正しく機能しています。

第4章 Reactフロントエンドの構築

次に、フロントエンドであるReactアプリケーションを構築し、Spring Bootバックエンドが提供するAPIを利用してタスク管理機能を実現します。

4.1 Reactプロジェクトの作成

Create React App (CRA) を使用して、新しいReactプロジェクトを作成します。CRAはReactアプリケーションのセットアップを簡単に行える公式推奨のツールチェインです。

ターミナルまたはコマンドプロンプトを開き、プロジェクトを作成したいディレクトリに移動して、以下のコマンドを実行します。TypeScriptを使用することを推奨します(JavaScriptでも構いませんが、型安全性のメリットがあります)。

“`bash
npx create-react-app task-manager-frontend –template typescript

または JavaScript で作成する場合

npx create-react-app task-manager-frontend

“`

npx は、インストールされていないnpmパッケージのコマンドを実行するためのツールです。create-react-app をグローバルにインストールせずに実行できます。--template typescript はTypeScriptテンプレートを使用してプロジェクトを作成します。

プロジェクトが作成されたら、プロジェクトディレクトリに移動します。

bash
cd task-manager-frontend

プロジェクト構造は以下のようになっているはずです。

task-manager-frontend/
├── node_modules/ <- 依存パッケージ
├── public/
│ ├── favicon.ico
│ ├── index.html <- アプリケーションのエントリポイントHTML
│ └── manifest.json
├── src/
│ ├── App.css
│ ├── App.test.tsx <- Appコンポーネントのテストファイル
│ ├── App.tsx <- アプリケーションのルートコンポーネント (TSXはTypeScript + JSX)
│ ├── index.css
│ ├── index.tsx <- アプリケーションのエントリポイントJavaScript/TypeScript
│ ├── logo.svg
│ ├── react-app-env.d.ts
│ ├── reportWebVitals.ts
│ └── setupTests.ts
├── .gitignore
├── package.json <- プロジェクトの設定ファイル(依存関係、スクリプトなど)
├── README.md
└── tsconfig.json <- TypeScriptの設定ファイル (TypeScriptテンプレートの場合)

アプリケーションを起動するには、以下のコマンドを実行します。

“`bash
npm start

または yarn start

“`

コマンドを実行すると、開発サーバーが起動し、デフォルトで http://localhost:3000 にアプリケーションが開きます。Create React Appの初期画面が表示されるはずです。

不要なファイル(App.test.tsx, logo.svg, reportWebVitals.ts, setupTests.ts など)や、App.css, index.css の内容はシンプルにするために削除または編集しておくと良いでしょう。src/App.tsxsrc/index.tsx を編集して、初期表示をシンプルなものに変更します。

例: src/App.tsx を以下のように編集

“`typescript jsx
import React from ‘react’;
import ‘./App.css’; // スタイルは必要に応じて調整

function App() {
return (

タスク管理アプリケーション


{/ ここにタスク管理コンポーネントを配置 /}

);
}

export default App;
“`

例: src/index.tsx はデフォルトのままで問題ありません。

4.2 バックエンドAPIとの連携準備

ReactアプリケーションからSpring BootバックエンドのAPIを呼び出すための準備をします。

4.2.1 HTTPクライアントのインストール

HTTPリクエストを送信するためのライブラリとして、ここでは axios を使用します。fetch APIがブラウザに標準搭載されていますが、axios はより高機能で使いやすいため、多くのプロジェクトで利用されています。

プロジェクトディレクトリで以下のコマンドを実行して axios をインストールします。

“`bash
npm install axios

または yarn add axios

“`

TypeScriptを使用している場合は、TypeScriptの型定義ファイルもインストールします。

“`bash
npm install –save-dev @types/axios

または yarn add –dev @types/axios

“`

4.2.2 プロキシ設定

開発中、React開発サーバーは http://localhost:3000 で、Spring Bootバックエンドは http://localhost:8080 で実行されます。Reactアプリケーションから /api/* のパスでAPIを呼び出す際に、毎回 http://localhost:8080/api/* とフルURLを指定するのは面倒ですし、CORSの問題も発生します。

Create React Appには、開発中のみ特定のパスへのリクエストをバックエンドにプロキシする機能があります。package.json ファイルに以下の設定を追加します。

json
{
"name": "task-manager-frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^1.0.0", // インストールしたaxiosのバージョンに合わせてください
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/axios": "^0.14.0", // インストールした型定義ファイルのバージョンに合わせてください
"@types/jest": "^27.5.2",
"@types/node": "^16.18.71",
"@types/react": "^18.2.47",
"@types/react-dom": "^18.2.18"
},
"proxy": "http://localhost:8080" // この行を追加
}

"proxy": "http://localhost:8080" という行を追加することで、開発サーバー(localhost:3000)宛てのAPIリクエスト(例えば /api/tasks)は、自動的に http://localhost:8080/api/tasks に転送されるようになります。これにより、React側では相対パス /api/tasks でAPIを呼び出すだけでよくなります。この設定は開発サーバーのみで有効であり、本番環境では別途プロキシ設定やCORS対応が必要です。

4.3 タスク管理コンポーネントの実装

タスク管理アプリケーションのUIを実装します。Reactのコンポーネント機能を使って、UIを部品化します。

src/components ディレクトリを作成し、その中に以下のコンポーネントファイルを作成します。

  • Task.ts or Task.tsx: タスクの型定義 (TypeScriptの場合)
  • TaskForm.tsx: 新しいタスクを入力するフォーム
  • TaskItem.tsx: 個別のタスクを表示し、完了状態の変更や削除を行う
  • TaskList.tsx: タスクのリストを表示し、子コンポーネントにデータを渡す

まずはタスクの型定義から。

src/components/Task.ts (TypeScript)

typescript
// バックエンドAPIから受け取るタスクデータの型を定義
export interface Task {
id: number;
title: string;
completed: boolean;
}

JavaScriptの場合はこのファイルは不要です。

次に、タスク一覧を表示する TaskList コンポーネントを作成します。

src/components/TaskList.tsx

“`typescript jsx
import React from ‘react’;
import TaskItem from ‘./TaskItem’;
import { Task } from ‘./Task’; // TypeScriptの場合

// Propsの型定義 (TypeScriptの場合)
interface TaskListProps {
tasks: Task[]; // 表示するタスクの配列
onTaskCompleteToggle: (id: number, completed: boolean) => void; // 完了状態変更時のコールバック関数
onTaskDelete: (id: number) => void; // 削除時のコールバック関数
}

// TaskList コンポーネント
// tasks という配列を受け取り、それぞれのタスクを TaskItem コンポーネントとして表示する
const TaskList: React.FC = ({ tasks, onTaskCompleteToggle, onTaskDelete }) => {
return (

    {/ tasks配列をマップして、各タスクに対してTaskItemコンポーネントを生成 /}
    {tasks.map((task) => (

    ))}

);
};

export default TaskList;
“`

TaskListtasks という配列を受け取り、各要素に対して TaskItem コンポーネントをレンダリングします。key propsはリストレンダリング時にReactが要素を識別するために必要です。また、タスクの完了状態変更と削除処理は親コンポーネントで管理するため、それらの処理を実行する関数をPropsとして子コンポーネントに渡します。

次に、個別のタスク項目を表示する TaskItem コンポーネントを作成します。

src/components/TaskItem.tsx

“`typescript jsx
import React from ‘react’;
import { Task } from ‘./Task’; // TypeScriptの場合

// Propsの型定義 (TypeScriptの場合)
interface TaskItemProps {
task: Task; // 表示するタスクオブジェクト
onCompleteToggle: (id: number, completed: boolean) => void; // 完了状態変更時のコールバック関数
onDelete: (id: number) => void; // 削除時のコールバック関数
}

// TaskItem コンポーネント
// 個別のタスクのタイトル、完了状態、操作ボタンを表示する
const TaskItem: React.FC = ({ task, onCompleteToggle, onDelete }) => {

// チェックボックスの変更を処理
const handleCompleteToggle = () => {
// 親コンポーネントから渡されたコールバック関数を呼び出す
// 引数としてタスクのIDと、現在の完了状態の反転(新しい完了状態)を渡す
onCompleteToggle(task.id, !task.completed);
};

// 削除ボタンのクリックを処理
const handleDeleteClick = () => {
// 親コンポーネントから渡されたコールバック関数を呼び出す
// 引数としてタスクのIDを渡す
onDelete(task.id);
};

return (

  • {/ タスク完了状態を示すチェックボックス /}

    {/ タスクのタイトルを表示。完了済みの場合は取り消し線を適用 /}

    {task.title}

    {/ 削除ボタン /}
  • );
    };

    export default TaskItem;
    “`

    TaskItemtask オブジェクトを受け取り、タイトルとチェックボックスを表示します。チェックボックスと削除ボタンにはイベントハンドラを設定し、クリックされた際に親から渡されたコールバック関数を呼び出します。チェックボックスの状態(checked)とタイトルのスタイル(textDecoration)は、task.completed の値に基づいて動的に変化させます。

    次に、新しいタスクを追加するための TaskForm コンポーネントを作成します。

    src/components/TaskForm.tsx

    “`typescript jsx
    import React, { useState } from ‘react’;

    // Propsの型定義 (TypeScriptの場合)
    interface TaskFormProps {
    onTaskAdd: (title: string) => void; // 新しいタスク追加時のコールバック関数
    }

    // TaskForm コンポーネント
    // 新しいタスクのタイトルを入力し、タスクを追加するフォーム
    const TaskForm: React.FC = ({ onTaskAdd }) => {
    // 入力フォームの値を管理するステート
    const [newTaskTitle, setNewTaskTitle] = useState(”);

    // 入力フィールドの値変更を処理
    const handleInputChange = (event: React.ChangeEvent) => {
    // 入力フィールドの現在の値をステートに設定
    setNewTaskTitle(event.target.value);
    };

    // フォーム送信を処理
    const handleSubmit = (event: React.FormEvent) => {
    event.preventDefault(); // フォームのデフォルトの送信(ページリロード)を防止

    // 入力値が空でないかチェック
    if (newTaskTitle.trim()) {
      // 入力値が空でなければ、親コンポーネントから渡されたコールバック関数を呼び出す
      // 引数として新しいタスクのタイトルを渡す
      onTaskAdd(newTaskTitle.trim());
      // タスク追加後、入力フィールドをクリア
      setNewTaskTitle('');
    }
    

    };

    return (
    // フォーム要素

    {/ タスクタイトル入力フィールド /}

    {/ タスク追加ボタン /}

    );
    };

    export default TaskForm;
    “`

    TaskForm は入力フィールドとボタンを持つフォームです。useState フックを使って入力フィールドの値を管理します。フォーム送信時には、onSubmit イベントハンドラで新しいタスクのタイトル(入力フィールドの値)を親コンポーネントに渡します。入力フィールドが空の場合は追加処理を行いません。

    最後に、これらのコンポーネントを組み合わせて、アプリケーション全体のロジックを管理する App コンポーネントを編集します。App コンポーネントはタスクの状態(リスト)を管理し、API呼び出しを行い、子コンポーネントにデータとコールバック関数を渡します。

    src/App.tsx

    “`typescript jsx
    import React, { useState, useEffect } from ‘react’;
    import axios from ‘axios’; // axiosをインポート
    import TaskList from ‘./components/TaskList’;
    import TaskForm from ‘./components/TaskForm’;
    import { Task } from ‘./components/Task’; // TypeScriptの場合
    import ‘./App.css’; // スタイルは必要に応じて調整

    function App() {
    // タスクリストを管理するステート
    const [tasks, setTasks] = useState([]); // TypeScriptの場合、初期値は空のTask配列

    // コンポーネントがマウントされたとき(初回表示時)にタスク一覧を取得する
    useEffect(() => {
    fetchTasks(); // fetchTasks関数を呼び出す
    }, []); // 空の依存配列を指定することで、マウント時のみ実行される

    // バックエンドからタスク一覧を取得する関数
    const fetchTasks = async () => {
    try {
    // プロキシ設定により、/api/tasks へのリクエストは http://localhost:8080/api/tasks へ転送される
    const response = await axios.get(‘/api/tasks’); // GETリクエストを送信
    setTasks(response.data); // 取得したデータをステートにセット
    } catch (error) {
    console.error(“タスクの取得に失敗しました”, error);
    // エラー表示など、必要に応じてエラーハンドリングを追加
    }
    };

    // 新しいタスクを追加する関数
    const handleTaskAdd = async (title: string) => {
    try {
    const newTask = { title, completed: false }; // 新しいタスクオブジェクトを作成
    // POSTリクエストで新しいタスクをバックエンドに送信
    const response = await axios.post(‘/api/tasks’, newTask);
    // バックエンドから返された(IDが付与された)新しいタスクを既存のタスクリストに追加
    setTasks([…tasks, response.data]);
    } catch (error) {
    console.error(“タスクの追加に失敗しました”, error);
    }
    };

    // タスクの完了状態を切り替える関数
    const handleTaskCompleteToggle = async (id: number, completed: boolean) => {
    try {
    // 更新対象のタスクを現在のリストから見つける
    const taskToUpdate = tasks.find(task => task.id === id);
    if (!taskToUpdate) return; // 見つからなければ何もしない

      // 更新データを準備(completed状態だけ変更)
      const updatedDetails = { ...taskToUpdate, completed: completed };
    
      // PUTリクエストでタスクを更新
      const response = await axios.put<Task>(`/api/tasks/${id}`, updatedDetails);
    
      // ステート内のタスクリストを更新(mapを使って対象のタスクだけ更新する)
      setTasks(tasks.map(task =>
        task.id === id ? response.data : task // IDが一致すればバックエンドからの最新データに置き換え
      ));
    } catch (error) {
      console.error(`タスクID ${id} の更新に失敗しました`, error);
    }
    

    };

    // タスクを削除する関数
    const handleTaskDelete = async (id: number) => {
    try {
    // DELETEリクエストでタスクを削除
    await axios.delete(/api/tasks/${id});
    // ステート内のタスクリストから削除されたタスクを除外(filterを使う)
    setTasks(tasks.filter(task => task.id !== id));
    } catch (error) {
    console.error(タスクID ${id} の削除に失敗しました, error);
    }
    };

    return (

    タスク管理アプリケーション


    {/ 新しいタスク追加フォーム /}

    {/ タスク一覧リスト /}

    );
    }

    export default App;
    “`

    App コンポーネントでは、useState フックでタスクの配列 tasks を管理します。useEffect フックを使用し、コンポーネントが最初にマウントされたとき(ページがロードされたとき)に fetchTasks 関数を呼び出し、バックエンドからタスク一覧を取得します。

    fetchTasks, handleTaskAdd, handleTaskCompleteToggle, handleTaskDelete といった非同期関数内で axios を使用してバックエンドAPIと通信します。それぞれの関数は await キーワードを使用してAPIレスポンスを待ち、成功した場合は setTasks を呼び出してステートを更新します。ステートが更新されると、ReactはUIを再レンダリングします。

    • タスク追加(handleTaskAdd): POSTリクエストで新しいタスクを送信し、返ってきたタスク(ID付き)を現在のリストの末尾に追加します。
    • 完了状態切り替え(handleTaskCompleteToggle): PUTリクエストで対象タスクの完了状態を更新し、バックエンドから返ってきた最新のタスクデータでリスト内の該当タスクを置き換えます。
    • タスク削除(handleTaskDelete): DELETEリクエストでタスクを削除し、リストから該当タスクを除外します。

    これらの関数は、それぞれ対応するUIコンポーネント(TaskFormTaskList/TaskItem)にPropsとして渡され、ユーザー操作に応じて呼び出されます。

    これで、ReactフロントエンドとSpring Bootバックエンドが連携する基本的なタスク管理アプリケーションが完成しました。

    4.4 アプリケーションの実行と動作確認

    1. Spring Bootバックエンドを起動します。

      • プロジェクトのルートディレクトリで ./mvnw spring-boot:run を実行するか、IDEからMainクラスを実行します。
      • アプリケーションが正常に起動し、8080ポートで待機していることを確認します。
    2. Reactフロントエンドを起動します。

      • task-manager-frontend ディレクトリに移動し、npm start を実行します。
      • ブラウザが開き、http://localhost:3000 でアプリケーションが表示されるはずです。

    画面が表示されたら、以下の操作を試してみてください。

    • 入力フィールドにタスク名を入力し、「追加」ボタンをクリックします。新しいタスクがリストに追加されることを確認します。(バックエンドのPOST APIが呼ばれています)
    • 追加したタスクのチェックボックスをクリックして、完了状態を切り替えます。タスク名のスタイルが変わり、バックエンドでも状態が更新されることを確認します。(バックエンドのPUT APIが呼ばれています)
    • タスクの「削除」ボタンをクリックします。リストからタスクが削除されることを確認します。(バックエンドのDELETE APIが呼ばれています)
    • ブラウザをリロードします。再度タスク一覧がバックエンドから取得され、追加・更新したタスクが表示されることを確認します。(バックエンドのGET APIが呼ばれています)

    これらの操作が意図通りに動作すれば、ReactとSpring Bootが正しく連携しています。

    第5章 デプロイについて(概要)

    開発環境でアプリケーションが動作することを確認したら、次は本番環境へのデプロイを検討します。ReactとSpring Bootアプリケーションは通常、独立してデプロイされます。

    5.1 バックエンド(Spring Boot)のデプロイ

    Spring Bootアプリケーションは、単一の実行可能なJARファイルとしてパッケージングできます。

    プロジェクトのルートディレクトリで以下のコマンドを実行すると、target ディレクトリ内に実行可能なJARファイルが生成されます。

    “`bash

    Maven Wrapper を使用する場合

    ./mvnw clean package

    Maven をグローバルにインストールしている場合

    mvn clean package

    “`

    生成されたJARファイル (target/task-manager-0.0.1-SNAPSHOT.jar のような名前) をサーバーに配置し、java -jar your-app.jar コマンドで実行できます。

    本番環境では、開発時に使用したH2 Database(インメモリ)ではなく、PostgreSQLやMySQLなどの永続化されるデータベースを使用するのが一般的です。application.properties のデータベース接続設定を本番用データベースの情報に書き換える必要があります。Spring Bootは多くのデータベースに対応しており、対応するJDBCドライバーを依存関係に追加すれば簡単に切り替えられます。

    デプロイ先としては、以下のような選択肢があります。

    • PaaS (Platform as a Service): Heroku, AWS Elastic Beanstalk, Google App Engine, Azure App Serviceなど。アプリケーションコードやJARファイルをアップロードするだけで、環境構築や実行基盤の管理をサービスプロバイダーが行ってくれるため、手軽にデプロイできます。
    • IaaS (Infrastructure as a Service): AWS EC2, Google Compute Engine, Azure Virtual Machinesなど。仮想マシンを借り、その上に自分でJava環境やアプリケーションをセットアップ・管理します。自由度が高い反面、運用管理の負担が大きくなります。
    • コンテナプラットフォーム: Dockerコンテナとしてアプリケーションをパッケージングし、KubernetesやAWS ECS/EKS、Google Kubernetes Engineなどのコンテナオーケストレーションプラットフォーム上にデプロイします。スケーラビリティや可用性の管理が容易になります。

    5.2 フロントエンド(React)のデプロイ

    Reactアプリケーションは、静的なHTML, CSS, JavaScriptファイルの集合としてビルドされます。

    task-manager-frontend ディレクトリで以下のコマンドを実行すると、build ディレクトリ内に本番用の静的ファイルが生成されます。

    “`bash
    npm run build

    または yarn build

    “`

    生成された build ディレクトリの内容(index.html, .css ファイル群, .js ファイル群など)を、任意の静的ファイルホスティングサービスにアップロードするだけでデプロイできます。

    デプロイ先としては、以下のような選択肢があります。

    • 静的サイトホスティングサービス: Netlify, Vercel, GitHub Pages, Firebase Hostingなど。Gitリポジトリと連携して、プッシュするだけで自動的にビルド・デプロイしてくれる機能が非常に便利です。
    • クラウドストレージサービス: AWS S3 + CloudFront, Google Cloud Storage + Cloud CDNなど。大量の静的ファイルを効率的に配信できます。CDNを組み合わせることで、ユーザーに最も近いサーバーからファイルを配信し、表示速度を向上させられます。
    • Webサーバー: Nginx, Apacheなど。これらのサーバーで静的ファイルを配信することも可能です。Spring BootのJARファイル内に静的ファイルをバンドルして、Spring Boot自体に配信させることも技術的には可能ですが、フロントエンドのビルドとバックエンドのビルド・デプロイを分けるのが一般的なアプローチです。

    本番環境では、ReactアプリケーションからバックエンドAPIを呼び出す際のURLを、開発環境の http://localhost:8080 から本番環境のAPIサーバーのURLに変更する必要があります。これは環境変数や設定ファイルを利用して切り替えるのが一般的です。また、フロントエンド側のデプロイ先とバックエンドAPIのオリジンが異なる場合、バックエンド側でのCORS設定(@CrossOrigin アノテーションなど)も本番環境のフロントエンドURLに合わせて調整する必要があります。

    第6章 さらなるステップ

    本ガイドで作成したアプリケーションは非常にシンプルです。ここからさらに機能を拡張したり、より実践的なアプリケーションに近づけるための次のステップを紹介します。

    • 認証・認可: ユーザー管理機能を追加し、APIエンドポイントへのアクセスを認証されたユーザーのみに制限したり、ユーザーのロールに基づいてアクセス権限を制御したりします。Spring SecurityはJava/Spring Bootアプリケーションで強力な認証・認可機能を提供します。React側では、ログイン画面の実装や、API呼び出し時に認証情報をヘッダーに含める(例: JWT – JSON Web Token)といった実装が必要になります。
    • 入力値検証 (Validation): フォームからの入力値やAPIリクエストボディのデータを検証し、不正なデータを受け付けないようにします。Spring BootではBean Validation API (javax.validation / jakarta.validation) と Hibernate Validator の組み合わせが一般的です。React側でもクライアントサイドで基本的なバリデーションを行うことで、ユーザーに素早くフィードバックを提供できます。
    • より複雑な状態管理: アプリケーションの状態が複雑になった場合、Reactの useStateuseContext だけでは管理が難しくなることがあります。Redux, Zustand, Recoil, Zustand などの状態管理ライブラリを導入することで、アプリケーション全体の状態を一元管理し、コンポーネント間のデータの受け渡しを効率化できます。
    • ルーティング: アプリケーション内に複数のページ(例: タスク一覧ページ、タスク詳細ページ、設定ページなど)を作成する場合、React Routerのようなルーティングライブラリが必要です。これにより、URLに基づいて表示するコンポーネントを切り替えるSPAのナビゲーションを実現できます。
    • テスト: アプリケーションの品質を保つためにはテストが不可欠です。
      • Spring Boot (バックエンド): JUnit, Mockito を使った単体テストや統合テスト、Spring Boot Test を使ったコントローラーやリポジトリのテストなどが考えられます。
      • React (フロントエンド): Jest, React Testing Library を使ったコンポーネントの単体テスト、統合テスト、Cypress や Playwright を使ったE2E (End-to-End) テストなどがあります。
    • エラーハンドリングとロギング: API呼び出しやサーバーサイドでのエラーが発生した場合に、ユーザーに適切なフィードバックを表示したり、サーバー側でエラー情報を詳細に記録したりする仕組みを構築します。Spring BootではAOPやControllerAdviceを使ったエラーハンドリングが有効です。フロントエンドでは、try...catch ブロックやエラー境界 (Error Boundaries) といったReactの機能を利用します。
    • コンテナ化 (Docker): Dockerを使ってアプリケーション(バックエンド、フロントエンド)をコンテナイメージとしてパッケージングすることで、開発環境と本番環境の差異をなくし、デプロイを容易にすることができます。
    • TypeScriptの活用: 本ガイドでも少し触れましたが、フロントエンド・バックエンドの両方でTypeScriptを活用することで、静的型チェックによる開発中のエラー削減やコードの可読性向上といったメリットが得られます。
    • モダンなフロントエンドビルドツール: Create React Appは手軽ですが、より高速なビルドや開発サーバーを提供するViteなどのツールも近年主流となっています。プロジェクトの規模や要件に応じて検討する価値があります。

    これらの技術や概念を学ぶことで、より堅牢で高機能なWebアプリケーションを開発できるようになります。

    まとめ

    本記事では、ReactとSpring Bootを組み合わせたモダンなWebアプリケーション開発の基本を、簡単なタスク管理アプリケーションの構築を通して学びました。

    • Reactを使って、コンポーネント指向で宣言的なUIを構築する方法。
    • Spring Bootを使って、迅速にRESTful APIを開発する方法。
    • axios とプロキシ設定を用いて、ReactからSpring Boot APIを呼び出す方法。
    • フロントエンドとバックエンドで役割を分担し、APIを通じて連携するアーキテクチャ。
    • 開発環境の準備から、最小限のアプリケーション実装、そしてデプロイの概要までを網羅しました。

    ReactとSpring Bootは、それぞれが成熟したエコシステムを持ち、大規模なアプリケーション開発にも耐えうる強力な技術です。これらの技術を組み合わせることで、開発効率とアプリケーションの品質を両立させることができます。

    この入門ガイドが、あなたがReact + Spring BootでのWebアプリケーション開発を始めるための一助となれば幸いです。今回作成したシンプルなアプリケーションをベースに、ぜひ様々な機能追加や改善に挑戦してみてください。実践を通して学ぶことが、エンジニアとしてのスキルアップの何よりの近道です。

    Happy Coding!


    コメントする

    メールアドレスが公開されることはありません。 が付いている欄は必須項目です

    上部へスクロール