💨

Reactの初歩(コンポーネント、Hooks)とReact Routerを使ったルーティング

2025/01/01に公開

概要

ReactはFacebookが開発したUIライブラリで、再利用可能な「コンポーネント」を用いて効率的にユーザーインターフェースを構築できます
このチュートリアルを通し、以下に示すReactの基本機能を学び、簡単だけど有用な個人アプリ開発をできるようになってもらえればと思います

  • 対象読者: Reactやフロントエンド開発が初めてのエンジニア
  • 到達点:
    1. コンポーネント作成とPropsの利用
    2. 状態管理(useState)の理解
    3. React Routerを使ったページ遷移の実装

このチュートリアルを通じて、以下のようなシンプルなアプリを作成するスキルを身につけられます

このチュートリアルで作れるアプリ例

チュートリアルで学ぶReactの基礎を活用することで、以下のようなシンプルなサイトを構築可能です

1. 簡易レシピまとめサイト

  • : クラシル
    レシピを一覧表示し、材料や調理手順を詳細ページで確認できる仕組みを作れます

2. 単語帳学習サイト

  • : mikan
    覚えたい単語を登録し、一覧表示や個別ページで詳細情報(意味や例文)を確認できるサイトを作成できます

3. クイズサイト

  • : QuizKnock
    質問と選択肢を表示し、正答を確認できるシンプルなクイズアプリを構築できます
    クイズリストを表示する機能や、詳細ページで質問の解答を確認する仕組みを作成可能です

このチュートリアルでやらないこと

このチュートリアルはReactの基本を学ぶミニマムなアプリを作れるようになるためのものです
そのため、以下のような高度な機能や技術は取り扱っていません

1. データの永続化やサーバーとの通信

  • : ユーザーデータやTODOリストを保存して、ブラウザを閉じた後もデータを維持する機能
    • Reactだけではデータを保存する機能(永続化)はありません
      このような機能を追加するには、Firebaseやバックエンドサーバー(Node.js、Railsなど)との連携が必要です

2. ユーザー認証

  • : ログイン・ログアウト機能や、認証済みユーザーのみがアクセスできるページの作成
    • 認証機能を実現するには、Firebase AuthenticationやOAuthを活用した外部サービスの連携が必要です

3. 複雑なUIデザインやアニメーション

  • : ドラッグ&ドロップ、動的なアニメーションや高度なレイアウトデザイン
    • Material-UIなどのスタイリングライブラリは使用しません

これらの要素は別途チュートリアルを作成予定です

1. イントロダクション

1.1 Reactとは?

Reactは再利用可能なコンポーネントベースの設計を提供するUIライブラリであり、次のような特徴があります

  • 学習コストが低い: コンポーネントとHooksを中心に簡潔に学べます
  • 拡張性が高い: Material UI(Google)Fluent UI(Microsoft) など多くの公式ライブラリが存在
  • コンポーネントの再利用: 一度作成したコンポーネントを複数の場所で使い回せるため、効率的な開発が可能

1.2 環境構築

このセクションでは、Reactの開発を始めるための環境構築を行います
今回は、GitHubにあるReact開発用のdevcontainerを利用し、効率的に開発環境をセットアップします

  1. GitHubリポジトリのクローン:

    • ターミナルで以下のコマンドを実行してリポジトリをクローンしてください
      git clone https://github.com/weworku/shared-devcon-react.git
      cd shared-devcon-react
      
    • 以下のような構成となっていることを確認してください
      /shared-devcon-react
      ├── /devcontainer
      │   └── devcontainer.json
      ├── Dockerfile
      ├── LICENSE
      ├── compose.yml
      ├── readMe.md
      └── work
      
  2. Devcontainerの起動:

    • クローンしたフォルダ内には、React開発用のdevcontainer設定が含まれています
    • Visual Studio Codeでshared-devcon-reactフォルダを開き、Reopen in Container オプションを選択してdevcontainerに接続します
      alt text
    • 接続が完了すると、コンテナ内で必要な依存関係がインストールされ、Reactプロジェクトの開発が可能になります
  3. Reactプロジェクトの作成:

    • devcontainerに接続したら、ターミナルで以下のコマンドを実行し、新しいReactプロジェクトを初期化します
    • このチュートリアルでは、Viteを使ってReactプロジェクトを作成します
      npm create vite@latest sample-todo-app -- --template react-ts
      
    • このコマンドにより、TypeScript対応のReactプロジェクトがsample-todo-appというフォルダ名で作成されます
  4. プロジェクトのディレクトリに移動:

    • 作成したsample-todo-appフォルダに移動し、依存関係をインストールしてプロジェクトを起動します
      cd sample-todo-app
      npm install
      npm run dev -- --host 0.0.0.0
      
  1. ブラウザで初期画面を確認:

    • npm run dev -- --host 0.0.0.0を実行すると、ローカルサーバーが立ち上がり、ブラウザで初期のReactアプリが表示されます
    • 初期のReactアプリを表示するURL(通常はhttp://localhost:5173)を開き、Reactの初期画面が表示されることを確認しましょう

    トラブルシューティング:

    • エラーが発生した場合:
      1. npm installが完了しているか確認してください
      2. 使用しているNode.jsのバージョンが16以上であることを確認してください

これで、React開発環境のセットアップが完了しました
次のセクションでは、この初期アプリのコードを少し変更して、Reactの基本的な仕組みを体験していきます

2. ReactコンポーネントとPropsの基礎

2.1 コンポーネントとは?

Reactでは、アプリケーションのUIを小さな単位「コンポーネント」(Component)に分けて構築します
コンポーネントは以下の特徴を持ちます

  • 再利用可能: 一度作成したUIを複数箇所で使用可能
  • Propsの利用: データを親から子に渡して動的にUIを変更可能

2.2 開発準備

Reactアプリの初期設定では、デフォルトのCSSファイルが含まれています
このチュートリアルでは、スタイリングは目的ではないため、初期CSSを削除します

1. CSSファイルの削除

srcフォルダ内にある以下のCSSファイルを削除してください。

  • src/index.css
  • src/App.css

削除方法は、ファイルを右クリックして「削除」を選択するか、エディタ外で直接削除します

2. CSSのインポートを削除

index.tsx および App.tsx 内にあるCSSのインポート文を削除してください

App.tsx

以下の行を削除してください

import './App.css';

2.3 TODOアイテムのコンポーネントを作成する

  • TodoItemコンポーネントの作成
    この例では、TodoItemコンポーネントにcontentというPropsを渡しています

    以下は、TODOリストの1項目を表示するシンプルなコンポーネントの例です
    このファイルは、src/componentsフォルダ内に保存してください

    // src/components/TodoItem.tsx
    // 現時点では使っていないため警告メッセージが出ます
    import React from 'react';
    
    function TodoItem(props: { content: string }) {
      return <li>{props.content}</li>;
    }
    
    export default TodoItem;
    
  • 解説: このコンポーネントは、contentという文字列のPropsを受け取り、それを<li>タグで表示するシンプルな構造です

2.4 AppコンポーネントでTODOリストを表示する

静的なTODOリストを表示する

  • 次に、Appコンポーネントに静的なTODOリストを表示します
  • ここでは、TODOの内容を配列として保持し、それをループ処理で表示する仕組みを導入します
  • App.tsxに以下のコードを記述します
    import React from 'react';
    import TodoItem from './components/TodoItem';
    
    function App() {
      const todos = ["開発準備", "TODOアイテムのコンポーネントを作成する", "AppコンポーネントでTODOリストを表示する"];
    
      return (
        <div>
          <h1>TODO List</h1>
          <ul>
            {todos.map((todo, index) => (
              <TodoItem key={index} content={todo} />
            ))}
          </ul>
        </div>
      );
    }
    
    export default App;
    

以下の画像のような表示になります
「2.4 AppコンポーネントでTODOリストを表示する」対応後にアプリを表示した状態

  • ポイント:
    • 配列todosにTODO項目を定義しています
    • map関数を使い、TODO項目ごとにTodoItemコンポーネントを呼び出し、表示しています
    • 注意: この段階では、配列に新しい項目を追加しても、表示は更新されません

よければtodosの変数の中を変えて、このチュートリアルに合わせてみてください

2.5 TODO追加フォームの作成

TodoFormコンポーネントの作成

  • 次に、新しいTODOを追加するための入力フォームを作成します
  • 現時点のフォームはTODOリストに反映されず、動作が未完成の状態であることを確認します
  • src/componentsフォルダに新しいファイル TodoForm.tsx を作成し、以下のコードを記述します
    // src/components/TodoForm.tsx
    import React from 'react';
    
    function TodoForm() {
      const handleAdd = () => {
        alert("TODO added!"); // 状態が無いため、まだ動作は確認のみ
      };
    
      return (
        <div>
          <input type="text" placeholder="Enter a new TODO"/>
          <button type="submit" onClick={handleAdd}>Add TODO</button>
        </div>
      );
    }
    
    export default TodoForm;
    

Appコンポーネントにフォームを組み込む

  • App.tsxを編集して、TODOリストの上にTodoFormを追加します
    import React from 'react';
    import TodoItem from './components/TodoItem';
    import TodoForm from './components/TodoForm'; // Add: TodoForm.tsx への参照を追加
    
    function App() {
      const todos = ["開発準備", "TODOアイテムのコンポーネントを作成する", "AppコンポーネントでTODOリストを表示する"];
    
      return (
        <div>
          <h1>TODO List</h1>
          {/* Add: TodoFromコンポーネントを追加 */}
          <TodoForm /> 
          <ul>
            {todos.map((todo, index) => (
              <TodoItem key={index} content={todo} />
            ))}
          </ul>
        </div>
      );
    }
    
    export default App;
    

以下の画像のような表示になります
「TODO追加フォーム」を追加後にアプリを表示した状態

  • ポイント:
    • TodoFormは、入力欄とボタンを持っていますが、現時点ではTODOリストに入力内容が反映されません
    • ボタンを押しても、入力されたデータはtodos配列に保存されないため、リストに追加されません

2.6 状態がないことを確認する

動作確認

  • TodoFormの入力欄にテキストを入力し、「Add TODO」ボタンを押してみましょう
  • この段階では、TODOリストは更新されず、入力したデータが表示に反映されません

次のステップへの導入

  • 現在、todos配列に新しい項目を追加しても表示が変わらない理由は、Reactで「状態」を管理していないためです
  • 次のセクションでは、ReactのHooksを使って状態を管理し、TODOリストを動的に更新する方法を学びます

3. Hooks入門(useState)

このセクションでは、Reactの「Hooks」の一つであるuseStateを学んでいきます
前のセクションで作成したTODOアプリに状態管理を追加し、TODOリストを動的に更新できるようにします

3.1 Hooksの概要とuseState

ReactのHooksは、関数型コンポーネントで「状態管理」や「副作用」を扱うための機能です
このチュートリアルではuseStateを使用します

基本構文

const [state, setState] = useState(initialValue);

それぞれ変数は以下の意味になります

  • state: 現在の状態の値
  • setState: 状態を更新するための関数
  • initialValue: 状態の初期値

3.2 TODOリストに状態を追加する

TODOリストを状態管理していくコードを追記していきます

useStateを使ってTODOリストを動的に管理します

  • AppコンポーネントでuseStateを使い、TODOリストを状態として保持
  • TodoFormからデータを受け取り、todosを更新
// App.tsx
// import React from 'react'; // Delete
import { useState } from 'react'; // add: stateに必要なimportを追加
import TodoItem from './components/TodoItem';
import TodoForm from './components/TodoForm';

function App() {
  // const todos = ["開発準備", "TODOアイテムのコンポーネントを作成する", "AppコンポーネントでTODOリストを表示する"]; // Delete
  const [todos, setTodos] = useState(["開発準備", "TODOアイテムのコンポーネントを作成する", "AppコンポーネントでTODOリストを表示する"]); // Add: stateの追加

  // stateの追加メソッドを定義
  const addTodo = (todo: string) => {
    setTodos([...todos, todo ]);
  };

  return (
    <div>
      <h1>TODO List</h1>
      {/* Add: TodoFromコンポーネントを追加 */}
      <TodoForm /> 
      <ul>
        {todos.map((todo, index) => (
          <TodoItem key={index} content={todo} />
        ))}
      </ul>
    </div>
  );
}
  • 状態をもつtodosuseStateで管理することで、TODOリストの変更がReactに認識されるようになります
  • この時点ではTODOリストの項目を追加する方法は未実装のため、次のステップで実装します

3.3 新しいTODOを追加する機能を実装

TodoFormコンポーネントで入力した値をApp.tsxの状態に追加する機能を実装します

TodoForm.tsx

TodoFormコンポーネントを編集します
App.tsxから状態と状態を変更するメソッドを受け取り、
新しいTODOを親コンポーネント(App.tsx)に渡します

import  { useState } from 'react'

function TodoForm(props: { addTodo: (todo: string) => void }) {
  const [inputValue, setInputValue] = useState("") // Add: テキストボックスの入力を保持する

  const handleAdd = () => {
    // alert("TODO added!"); // Delete
    props.addTodo(inputValue) // Add: 親コンポーネント管理のstateにTODO項目を追加
    setInputValue("") // Add: TODOを保存したので入力欄をリセット
  }

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)} // Add: 入力のたび、入力欄の状態を更新
        placeholder="Enter a new TODO"
      />
      {/* Add: ボタンクリック時にTODOを追加 */}
      <button type="submit" onClick={handleAdd}>Add TODO</button>
    </div>
  )
}

export default TodoForm

3.4 動作確認

  1. アプリケーションを起動し、TODOリストが表示されることを確認します
  2. TodoFormにテキストを入力し、「Add TODO」ボタンを押します
  3. 入力したテキストがリストに追加されることを確認します

次のステップ

ここまででできるようになったことは以下の通りです

  • ReactのuseStateを使った状態管理
  • TODOリストのデータを管理し、動的に表示する仕組みの実装
  • 入力フォームからデータを取得してリストに追加する機能の実装

これらを通じて、ユーザーの入力やアクションに対して表示を動的に変更することができるようになりました

次のセクションでは、React Routerを使ってTODOリストにページ遷移の機能を追加します

4. ルーティングの基礎(React Router)

このセクションでは、Reactアプリケーションにページ遷移機能を追加するためのReact Routerの基礎を学びます
TODOアプリにルーティングを組み込み、リスト表示ページと詳細ページのような構造を実現します

4.1 React Routerとは?

  • React Routerの概要:

    • React Routerは、Reactアプリケーションにルーティング機能を追加するためのライブラリです
    • ページ遷移や動的なルーティングを簡単に実現できます
    • ブラウザの履歴機能やブックマーク、リンク共有をサポートし、ユーザーに直感的なナビゲーション体験を提供します
  • 主な機能:

    • ページ間の移動
    • 動的なルート(URLパラメータの使用)
    • ネストされたルートの定義
  • このセクションで学ぶ内容:

    • 基本的なルート設定
    • ルート間のナビゲーション
    • URLパラメータの使用

4.2 React Routerのインストール

  • インストールコマンド:
    • React Routerをインストールします
    npm install react-router-dom
    

4.3 ルートの定義

  • ルートの基本設定:
    • アプリケーションのエントリーポイントであるApp.tsxにReact Routerを導入します
    • 以下のコードでReact Routerを設定します
import { useState } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom' // Add: React Routerに必要なimport
import Home from './pages/Home' // Add: Homeページコンポーネントのimport
import TodoDetails from './pages/TodoDetails' // Add: TodoDetailsページコンポーネントのimport

function App() {
  const [todos, setTodos] = useState([
    "開発準備",
    "TODOアイテムのコンポーネントを作成する",
    "AppコンポーネントでTODOリストを表示する"
  ])

  const addTodo = (todo: string) => {
    setTodos([...todos, todo])
  }

  return (
    <Router> {/* Add: Routerでアプリ全体をラップ */}
      <Routes> {/* Add: Routesでルーティングを設定 */}
        <Route path="/" element={<Home todos={todos} addTodo={addTodo} />} /> {/* Add: ホームページのルート */}
        <Route path="/todo/:id" element={<TodoDetails todos={todos} />} /> {/* Add: 詳細ページのルート */}
      </Routes>
    </Router>
  )
}

export default App
  • ポイント:
    • Routerを使用してアプリ全体をラップし、ルーティングを有効化
    • Routes内にRouteを定義し、パスに応じたコンポーネントを表示
    • ホームページはHome、詳細ページはTodoDetailsを利用

4.4 ホームページの作成

  • Home.tsx:
    • ホームページにTODOリストを表示し、各TODO項目へのリンクを追加します
    • src/pagesフォルダを作成し新しいファイル Home.tsx を作成、以下のコードを記述します
// src/pages/Home.tsx
import { Link } from 'react-router-dom'
import TodoItem from '../components/TodoItem' // Add: TodoItem.tsx への参照を追加
import TodoForm from '../components/TodoForm' // Add: TodoForm.tsx への参照を追加

function Home(props: { todos: string[]; addTodo: (todo: string) => void }) {
  return (
    <div>
      <h1>TODO List</h1>
      <TodoForm addTodo={props.addTodo} /> {/* Add: TodoFormを表示 */}
      <ul>
        {props.todos.map((todo, index) => (
          /* keyはReact内部で使い、indexはpropsとして渡す */
          <TodoItem key={index} index={index} content={todo} /> 
        ))}
      </ul>
    </div>
  )
}

export default Home

4.5 個別のTODO項目を表示するコンポーネントの修正

  • TodoItem.tsx:
    • TodoItem.tsxを修正して、URLで個別のTodoに遷移できるようにします
// src/components/TodoItem.tsx
import React from 'react';
import { Link } from 'react-router-dom' // Add: todoへの遷移にLinkを利用

function TodoItem(props: { index: number, content: string }) {
  return (
    <li>
      {/* Add: 各TODOにリンクを追加 */}
      <Link to={`/todo/${props.index}`}>{props.content}</Link> 
    </li>
  )
}

export default TodoItem

4.6 詳細ページの作成

  • TodoDetails.tsx:
    • リストの項目をクリックすると詳細ページが表示されるようにします
    • src/pagesフォルダに新しいファイル TodoDetails.tsx を作成、以下のコードを記述します
// src/pages/TodoDetails.tsx
import { useParams, Link } from 'react-router-dom' // Add: URLパラメータを取得するuseParamsとリンク用のLinkをimport

function TodoDetails(props: { todos: string[] }) {
  const { id } = useParams<{ id: string }>() // Add: URLパラメータからIDを取得
  const todo = props.todos[Number(id)] // Add: IDを元にTODOリストから項目を取得

  if (!todo) {
    return <p>TODO not found</p> // Add: 該当するTODOがない場合のエラーメッセージ
  }

  return (
    <div>
      <h1>TODO Details</h1>
      <p>{todo}</p> {/* Add: TODOの詳細を表示 */}
      <Link to="/">Back to TODO List</Link> {/* Add: ホームページへのリンク */}
    </div>
  )
}

export default TodoDetails

4.7 動作確認

  1. 確認する内容:
  • アプリを起動し、ホームページでTODOリストが表示されることを確認
  • 各TODO項目をクリックすると、詳細ページに遷移して内容が表示されることを確認
  • 詳細ページに「Back to TODO List」のリンクがあり、クリックするとホームページに戻れることを確認
  1. 追加のポイント:
  • URLパラメータを変更することで、動的に異なるTODOの詳細を表示できることを確認

4.8 次のステップ

これまでのチュートリアルを通じて、Reactの基礎(コンポーネント、状態管理、ルーティング)を使ったTODOリストアプリを完成させました
ここで学んだ内容を振り返ります

  • 学んだこと:
    1. ReactのuseStateを使った状態管理
    2. データの動的な管理と表示
    3. React Routerを使ったページ遷移とURLパラメータの使用

これらを通じて、Reactを使ったシンプルなアプリケーションの構築手順を一通り学ぶことができました

5. 終わりに

次に進むステップとして、さらに高度なアプリケーション開発に挑戦してみましょう
以下はおすすめの学習内容です:

  • UIコンポーネントライブラリの利用: Material UI(Google)やFluent UI(Microsoft)を使って、プロフェッショナルなデザインを取り入れる
  • 高度な状態管理: ReduxやZustandを利用して、大規模なアプリケーションの複雑な状態を効率的に管理する
  • APIとの通信: AxiosやFetch APIを使い、サーバーとデータをやり取りする仕組みを学ぶ

この記事で得た知識をベースに、さらに大きな目標に向けて一歩ずつ進んでいってください!
次回の記事では、Material UIを活用したスタイリッシュなUIデザインを取り入れる方法を紹介できればと思っています
お楽しみに!!

Discussion