タイピングアプリ開発：Reactで作るシンプルなタイピングアプリをDockerで動かすまでの手順

## はじめに
本記事では、Docker環境でReactを使用してシンプルなタイピングアプリを作成する手順について説明します。

今回は、ユーザーが指定された単語をタイピングし、タイピング速度を確認できるシンプルなアプリを実装しています。

本記事はITスクールの課題としてアウトプット学習を目的に作成したもので、個人の備忘録レベルの内容ですのでご了承ください。

## 必要なツール

:::note
**私の環境はM1チップ搭載のMacOSですが、本記事のハンズオンで使用するツールは以下の通りです。**
・``Docker``
・``Docker Compose``
・``Node.js（バージョン14以上推奨）``
・``npm（Node Package Manager）``
:::

## 作成したタイピングアプリのデモ動画

以下はタイピングアプリのデモ動画です。ユーザーが提示された単語をタイピングすると、正確に入力したタイミングで結果が表示されます。

![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/c53b6dac-c2c6-4146-ec38-582cdce20bb3.gif)

:::note warn
**気軽に楽しめるアプリとして、タイピング練習のきっかけになれば幸いです。**
:::

## ディレクトリ構成
以下のようなディレクトリ構成でReactアプリを構築します。この構成により、タイピングアプリのファイルを適切に配置し、Docker環境で動作させることができます。

```bash
typing-app/
│
├── node_modules/         # Node.jsのモジュールが格納されるディレクトリ
│
├── public/               # 公開用のファイル
│   └── index.html        # アプリケーションのエントリーポイントとなるHTMLファイル
│
├── src/                  # ソースコードのディレクトリ
│   ├── Typing.js         # タイピングのロジック
│   ├── Typing.css        # タイピングのスタイルシート
│   ├── index.js          # アプリケーションのエントリーポイント
│   └── index.css         # アプリケーションのスタイルシート
│
├── .dockerignore         # Dockerビルド時に無視するファイル
├── Dockerfile            # Dockerイメージを作成するための設定ファイル
├── docker-compose.yml    # Docker Composeの設定ファイル
├── package.json          # プロジェクトの依存関係やスクリプトを管理するファイル
└── README.md             # プロジェクトの説明や使い方を記載したファイル（任意）
```

このディレクトリ構成を作成するために、以下のコマンドを実行して初期ファイルを生成し、不要なファイルを削除して整理します。

```
npx create-react-app tictactoe
```

:::note warn
**上記のコマンドを実行するとデフォルトで多数のファイルが作成されますが、ここでは不要なファイルを削除して進めます。**
:::

## ステップ1: プロジェクトの作成
### Dockerfileの作成
まず、プロジェクトのルートディレクトリに以下の内容で ``Dockerfile`` を作成します。

```Dockerfile
# Dockerfile
FROM node:14

# 作業ディレクトリの設定
WORKDIR /app

# 依存関係のインストール
COPY package*.json ./
RUN npm install

# アプリケーションのソースをコピー
COPY . .

# アプリケーションをビルド
RUN npm run build

# アプリケーションを提供する
CMD ["npm", "start"]
```

この ``Dockerfile`` は、Dockerイメージを作成するための設定ファイルです。Node.js 環境を構築し、アプリケーションの依存関係をインストールし、最終的にアプリをビルドします。

### docker-compose.ymlの作成
次に、プロジェクトのルートディレクトリに以下の内容で ``docker-compose.yml`` を作成します。

```docker-compose.yml
version: '3'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
    environment:
      - CHOKIDAR_USEPOLLING=true
```

このファイルは、Docker Composeを使用してアプリケーションのサービス構成を定義するものです。アプリケーションのビルド、ポートの公開、ボリュームの設定などを管理します。

## ステップ2: Reactアプリの作成
ここでは、タイピングアプリの機能を実装するためのファイルをプロジェクトに追加します。

### Typing.js
以下は ``Typing.js`` のコードです。このコードでは、ランダムに表示される単語を正確に入力するためのタイピングロジックを実装しています。

```Typing.js
// src/Typing.js
import React, { useState, useEffect } from 'react';
import './Typing.css';

const Typing = () => {
  const words = ["タイピング", "プログラミング", "React", "JavaScript", "開発", "コード", "デバッグ", "フロントエンド", "バックエンド", "アルゴリズム", "データベース"];
  
  const [input, setInput] = useState("");
  const [word, setWord] = useState("");
  const [result, setResult] = useState("");

  // 単語をランダムに選択する関数
  const pickRandomWord = () => {
    const randomIndex = Math.floor(Math.random() * words.length);
    setWord(words[randomIndex]);
  };

  useEffect(() => {
    pickRandomWord(); // コンポーネントがマウントされたときに単語を選択
  }, []);

  const handleChange = (e) => {
    setInput(e.target.value);
    if (e.target.value === word) {
      setResult("成功！");
      setInput("");
      pickRandomWord(); // 成功したら新しい単語を選択
    }
  };

  return (
    <div className="container">
      <h1>タイピングゲーム</h1>
      <p>次の単語を入力してください: <strong>{word}</strong></p>
      <input type="text" value={input} onChange={handleChange} />
      <p>{result}</p>
    </div>
  );
};

export default Typing;
```

### Typing.css
以下は ``Typing.css`` のコードです。タイピングフィールドと結果表示にスタイルを適用しています。

```Typing.css
/* src/Typing.css */
body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background-color: #e1f5fe;
  margin: 0;
}

.container {
  text-align: center;
  font-family: 'Arial', sans-serif;
}

input {
  font-size: 24px;
  padding: 10px;
  margin-top: 20px;
}

p {
  font-size: 20px;
}
```

### index.js
以下は ``index.js`` のコードです。Reactのエントリーポイントとして、アプリケーションをレンダリングしています。

```index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import Typing from './Typing';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Typing />
  </React.StrictMode>
);
```

### index.css
次に、全体のスタイルを設定するための ``index.css`` ファイルをプロジェクトに追加します。

```index.css
/* src/index.css */
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  background-color: #f0f0f0;
}
```

## ステップ3: アプリの起動
最後に、以下のコマンドでアプリケーションを起動します。

```bash
# Docker Composeを使ってアプリケーションを起動
docker-compose up
```

ブラウザで、``http://localhost:3000/``を入力すると、以下のページが表示されていれば成功です。

![スクリーンショット 2024-11-03 17.05.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/93801e2e-d05d-32fa-786b-14724a5c4aff.png)

実際に``フロントエンド``と入力すると、画面に``成功!``と表示され、次の単語に遷移します。

![スクリーンショット 2024-11-03 17.06.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/49066744-25a1-17d2-d90e-1bf878e46833.png)

``フロントエンド``を入力後の実際の画面と動きは以下になります。

![スクリーンショット 2024-11-03 17.08.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/c766e5fd-f0ce-08ce-89c0-1a2d1b4eea70.png)

今回のタイピングアプリは、簡単な単語入力で正確性を確認できるシンプルな機能ですが、個人的には暇つぶしに最適だと感じました！

## まとめ

本記事では、Dockerを使用してReactでタイピングアプリを作成しました。

シンプルな機能からスタートしていますが、今後はタイピング速度や精度を測定する機能も追加していく予定です。

フロントエンド側のアプリ開発も終盤に差し掛かってきたので、この調子で頑張ります！

## 参考記事

https://qiita.com/Terao-Takumi/items/bc4f543b51b8b31e0522

https://zenn.dev/grazie/articles/077982584de3c0