「タスク管理アプリ」を作りながらReactとTypeScriptを学ぼう


このチュートリアルでは、Vite、TypeScript、そして Tailwind CSS を使用してシンプルなタスク管理アプリを作成する方法を解説します。

こんな感じの「タスク管理アプリ」を 10 分ぐらいで作れます。

![スクリーンショット 2024-09-29 20.22.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364501/f7099c0c-6387-c3ea-d7e8-d875993d6f55.png)

React と TypeScript の基礎を丁寧に解説していますので、初心者の方でも安心して取り組むことができるかと思います！

では、早速始めていきましょう！

## 1. プロジェクトの作成

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

ターミナル（or コマンドプロンプト、PowerShell）を開き、以下のコマンドを実行します。

```bash
npm create vite@latest task-management-app -- --template react-ts
```

このコマンドは以下のことを行っています。

1. Vite を使用して React + TypeScript のプロジェクトを作成
2. プロジェクト名を「task-management-app」に設定

終わりましたら、以下のようなディレクトリ構造が作成されます。

では、作成したプロジェクトディレクトリに移動します。

```bash
cd task-management-app
```

:::note info
今回はビルドツールとして「Vite」を使用しています。

Vite は高速な開発環境とビルドツールを提供するモダンなフロントエンド開発環境です。
:::

## 2. 依存関係のインストール

プロジェクトディレクトリ内で以下のコマンドを実行します。

```bash
npm install
```

`npm install`は、プロジェクトの基本的な依存関係をインストールします。

次に、Tailwind CSS をプロジェクトに追加します。

以下のコマンドを実行してください。

```bash
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
```

このコマンドで、Tailwind CSS とその関連パッケージをインストールできます。

<details><summary>各パッケージの説明</summary>

- tailwindcss: スタイリングのためのユーティリティファースト CSS フレームワーク
- postcss: CSS を変換するためのツール
- autoprefixer: ベンダープレフィックスを自動的に追加する PostCSS プラグイン

</details>

では次に、Tailwind CSS を設定していきます。

## 3. Tailwind CSS の設定

Tailwind CSS を使用するための設定ファイルを生成します。

以下のコマンドを実行してください。

```bash
npx tailwindcss init -p
```

このコマンドで、`tailwind.config.js`と`postcss.config.js`の 2 つの設定ファイルを生成します。

次に、`tailwind.config.js`ファイルを以下のように編集します。

```javascript:tailwind.config.js
module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```

上記の `content`で、 Tailwind CSS のユーティリティクラスを使用するファイルのパターンを指定しています。

ここでは、`index.html`と`src`ディレクトリ内の JavaScript/TypeScript ファイルを対象にしています。

これで Tailwind CSS の基本的な設定が完了しました。

ただ、これだけでは Tailwind CSS のスタイルが適用されないため、プロジェクトの CSS ファイルを編集する必要があります。

## 4. CSS ファイルの作成

`src/index.css`ファイルを以下の内容で置き換えます。

```css:src/index.css
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
```

Tailwind CSS の基本スタイル、コンポーネントスタイル、ユーティリティクラスをプロジェクトにインポートしていますので、Tailwind CSS のすべての機能を使用できるようになります。

## 5. 型定義の作成

TypeScript を使用する利点の 1 つは、型定義によってコードの安全性を高められることです。

では早速、タスク管理アプリで使用する「タスク」の型を定義しましょう。

今回はタスク一つひとつが持つ ID とテキストの 2 つのプロパティを持つオブジェクトを定義します。

`src/types.ts`ファイルを作成し、以下の内容を記述します。

```typescript:src/types.ts
export interface Task {
  id: number;
  text: string;
}
```

<details><summary>Task 型定義の説明</summary>

- `Task`は、`id`と`text`の 2 つのプロパティを持つオブジェクトを表します。
- `id`は数値型（number）で、各タスクを一意に識別するために使用されます。
- `text`は文字列型（string）で、タスクの内容を表します。

</details>

型定義を使用することで、コード内でタスクを扱う際に、ID やテキストが適切な型であることを保証し、潜在的なバグを防ぐことができます。

例えば、間違った型の値を代入しようとすると、TypeScript がエラーを検出してくれます。
（例：`id: '123'`など）

## 6. コンポーネントの作成

React では、UI を再利用可能な部品（コンポーネント）に分割することで、効率的な開発が可能になります。

今回のアプリでは、タスクの入力フォームとタスクリストの 2 つの主要なコンポーネントを作成します。

まず、`src/components`ディレクトリを作成してください。このディレクトリ内に、以下の 2 つのファイルを作成します。

- `TaskForm.tsx`: 新しいタスクを追加するためのフォームを表すコンポーネント
- `TaskList.tsx`: タスクのリストを表示するコンポーネント

ファイルが作れたら、それぞれのコンポーネントの中身を作成していきます。

### TaskForm.tsx

これは新しいタスクを追加するためのフォームを表すコンポーネントです。

中身を以下のように記述してください。

```tsx:src/components/TaskForm.tsx
import React, { useState, useCallback } from 'react';

interface TaskFormProps {
  addTask: (text: string) => void;
}

const TaskForm: React.FC<TaskFormProps> = ({ addTask }) => {
  const [task, setTask] = useState('');

  const handleSubmit = useCallback((e: React.FormEvent) => {
    e.preventDefault();
    if (task.trim()) {
      addTask(task);
      setTask('');
    }
  }, [task, addTask]);

  return (
    <form onSubmit={handleSubmit} className="flex gap-2 mb-4">
      <input
        type="text"
        value={task}
        onChange={(e) => setTask(e.target.value)}
        placeholder="新しいタスクを入力"
        className="flex-grow px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
      />
      <button
        type="submit"
        className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
      >
        追加
      </button>
    </form>
  );
};

export default TaskForm;
```

このコンポーネントで使っている React の機能や、JavaScript のコードのポイントを簡単に説明しておきます。

<details><summary>以下、TaskFormコンポーネントの解説</summary>

1. `useState` フック:

   - `task` という状態変数を作成し、入力フィールドの現在の値を保持します。
   - `setTask` 関数を使って、ユーザーの入力に応じて `task` の値を更新します。

2. `useCallback` フック:

   - `handleSubmit` 関数をメモ化（最適化）します。
   - フォームが送信されたときに呼び出され、新しいタスクを追加します。

3. Tailwind CSS クラス:

   - `className` 属性に直接スタイルを適用しています。
   - 例えば、`flex gap-2 mb-4` はフレックスボックスレイアウト、要素間の間隔、下部のマージンを設定します。

4. フォームの挙動:

   - `preventDefault()` を使用して、フォーム送信時のページリロードを防いでいます。
   - 入力が空でない場合のみ、新しいタスクを追加します。

5. アクセシビリティ:
   - `focus` 状態のスタイリングにより、キーボード操作性を向上させています。

</details>

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

### TaskList.tsx

これはタスクのリストを表示するコンポーネントです。

中身を以下のように記述してください。

```tsx:src/components/TaskList.tsx
import React from 'react';
import { Task } from '../types';

interface TaskListProps {
  tasks: Task[];
  removeTask: (id: number) => void;
}

const TaskList: React.FC<TaskListProps> = ({ tasks, removeTask }) => {
  return (
    <ul className="space-y-2">
      {tasks.map((task) => (
        <li key={task.id} className="flex items-center justify-between p-2 bg-gray-100 rounded-md">
          <span>{task.text}</span>
          <button
            onClick={() => removeTask(task.id)}
            className="px-2 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500"
          >
            削除
          </button>
        </li>
      ))}
    </ul>
  );
};

export default TaskList;
```

<details><summary>以下、TaskListコンポーネントの解説</summary>

1. Props 型定義:

   - `TaskListProps` インターフェースで、このコンポーネントが受け取るプロパティの型を定義しています。
   - `tasks` は `Task` オブジェクトの配列で、表示するタスクのリストです。
   - `removeTask` は関数で、タスクを削除するために使用されます。

2. タスクのマッピング:

   - `tasks.map()` を使用して、各タスクをリストアイテムにレンダリングしています。

3. キーの使用:

   - 各リストアイテムに `key` プロパティを設定しています
   - これがないと、React がリストの変更を追跡できなくなりますので、忘れずに設定してください。

4. イベントハンドリング:

   - 削除ボタンに `onClick` イベントを設定し、対応するタスクを削除できるようにしています。

5. Tailwind CSS クラス:
   - リストアイテムのレイアウトやスタイリングに Tailwind CSS のユーティリティクラスを使用しています。

</details>

これらのコンポーネントにより、タスクの追加と削除を行うための UI が作成されました。

次は、これらのコンポーネントを組み合わせて、アプリケーション全体を構築していきます。

## 7. App.tsx の更新

最後に、アプリケーションのメインコンポーネントである `App.tsx` を更新します。

このファイルでは、先ほど作成した `TaskForm` と `TaskList` コンポーネントを統合し、アプリケーション全体の状態を管理します。

`src/App.tsx` ファイルを以下の内容で置き換えてください。

```tsx
import React, { useState, useCallback } from 'react';
import TaskForm from './components/TaskForm';
import TaskList from './components/TaskList';
import { Task } from './types';

const App: React.FC = () => {
  const [tasks, setTasks] = useState<Task[]>([]);

  const addTask = useCallback((newTask: string) => {
    setTasks((prevTasks) => [...prevTasks, { id: Date.now(), text: newTask }]);
  }, []);

  const removeTask = useCallback((id: number) => {
    setTasks((prevTasks) => prevTasks.filter((task) => task.id !== id));
  }, []);

  return (
    <div className="container mx-auto p-4 max-w-md">
      <div className="bg-white shadow-md rounded-lg p-6">
        <h1 className="text-2xl font-bold text-center mb-4">タスク管理アプリ</h1>
        <TaskForm addTask={addTask} />
        <TaskList tasks={tasks} removeTask={removeTask} />
      </div>
    </div>
  );
};

export default App;
```

<details><summary>以下、Appコンポーネントの解説</summary>

1. 状態管理:

   - `useState` フックを使用して `tasks` 状態を管理しています。
   - これは `Task` オブジェクトの配列です。

2. タスク追加機能:

   - `addTask` 関数は `useCallback` でメモ化されています。
   - 新しいタスクを作成し、既存のタスクリストに追加します。
   - `Date.now()` を使用して一意の ID を生成しています。

3. タスク削除機能:

   - `removeTask` 関数も `useCallback` でメモ化されています。
   - 指定された ID のタスクをリストから削除します。

4. コンポーネントの組み合わせ:
   - `TaskForm` と `TaskList` コンポーネントを使用して、UI を構築しています。
   - 必要な props（`addTask`、`tasks`、`removeTask`）を各コンポーネントに渡しています。

この `App` コンポーネントは、アプリケーション全体の構造と状態管理を担当します。

タスクの追加と削除のロジックをここで定義し、それらの機能を子コンポーネントに渡すことで、整理された構造を維持しています。

</details>

:::note info
今回のアプリに限らず、React アプリケーションでは、親コンポーネントが状態を管理し、子コンポーネントに渡すというパターンが一般的です。
:::

## 8. アプリケーションの実行

これで、タスク管理アプリの開発が完了しました！

では、アプリケーションを起動して動作を確認しましょう。以下のコマンドを実行してください。

```bash
npm run dev
```

このコマンドは開発サーバーを起動します。

コマンドが成功すると、ターミナルに表示される URL をブラウザで開くことができます（通常は `http://localhost:5173` です）。

ブラウザでアプリケーションが表示されたら、以下の操作を試してみてください。

1. 入力フォームにタスクを入力し、「追加」ボタンをクリックします。
2. 新しいタスクがリストに追加されることを確認します。
3. タスクの横にある「削除」ボタンをクリックして、タスクを削除できることを確認します。

実際に動かしてみると、以下のようになります。

![スクリーンショット 2024-09-29 20.22.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364501/300d560a-e8b5-afdc-d506-8f933b0e341c.png)

入力フォームにテキストを入力して「追加」ボタンをクリックすると、タスクが追加されます。

![スクリーンショット 2024-09-29 20.22.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364501/dc9d3eb7-dffc-d517-8ab3-8a13402eee3a.png)

![スクリーンショット 2024-09-29 20.22.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364501/f7099c0c-6387-c3ea-d7e8-d875993d6f55.png)

もちろん、削除ボタンをクリックするとタスクが削除されます。

![スクリーンショット 2024-09-29 20.22.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364501/300d560a-e8b5-afdc-d506-8f933b0e341c.png)

これで、React を使用した基本的なタスク管理アプリケーションが完成しました！

## まとめ

いかがでしたでしょうか？

このチュートリアルを通じて、以下の重要な概念とツールについて学ぶことができました。

1. Vite: 高速な開発環境とビルドツールを提供するモダンなフロントエンド開発環境
2. TypeScript: JavaScript に型システムを追加し、コードの品質と保守性を向上させる言語
3. Tailwind CSS: 効率的なスタイリングを可能にするユーティリティファーストの CSS フレームワーク
4. React コンポーネント: UI を再利用可能な部品に分割する概念
5. React フック（useState, useCallback）: 関数コンポーネントで状態や副作用を管理するための機能

このアプリケーションをベースに、さらに機能を追加したり、デザインをカスタマイズしたりして、自分だけのオリジナルアプリを作ってみると面白いかもしれませんね。

例えば、以下のような機能を追加してみるのも良いでしょう。

- タスクの完了状態を管理する（チェックボックスの追加）
- タスクの編集機能
- タスクの優先度や期限の設定
- ローカルストレージを使用したタスクの永続化

## ちょっと宣伝：もっと React を学びたい方へ

個人的に技術ブログも書いており、React に関する記事も多数公開しています。

興味があれば、以下の記事もチェックしていただけると大変励みになります...！

https://musclecoding.com/react-books-recommended/