ReactとVercelで作るモダンな電卓アプリ「Dentaku」を作りました

![2024-07-29 15.13の画像.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806587/9b01ad07-9ec7-f0ea-b92a-f455cf0996e0.jpeg)

こんにちは、皆さん！今回は、Reactを使ったモダンな電卓アプリケーション「Dentaku」を開発し、Vercelにデプロイした経験をシェアしたいと思います。プロジェクトの全体像から、具体的な手順まで詳しく紹介しますので、ぜひ参考にしてください。

## アプリリンク
https://dentaku-kappa.vercel.app/

## プロジェクトの概要

「Dentaku」は、シンプルでスタイリッシュな電卓アプリケーションです。最新のWeb技術を活用し、ユーザーに快適な使用感を提供することを目指しています。以下はプロジェクトの主な特徴です。

- **フロントエンドフレームワーク**: React
- **ホスティング**: Vercel
- **スタイル**: Tailwind CSS
- **機能**: 基本的な計算機能（加算、減算、乗算、除算）

## アプリケーションの機能
基本的な機能
数字入力: 0から9までの数字ボタンを使って、計算したい数値を入力できます。
小数点入力: 小数点ボタンを使って、小数を入力できます。
四則演算: 加算、減算、乗算、除算の基本的な計算機能を提供します。
結果表示: =ボタンを押すと計算結果が表示されます。
クリア機能: Clearボタンを押すと、現在の入力と計算結果がクリアされます。

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

### 1. Create React Appの利用

まずは、Create React Appを使ってReactプロジェクトを作成しました。

```sh
npx create-react-app dentaku
cd dentaku
```

### 2. Tailwind CSSのインストールと設定

次に、Tailwind CSSをインストールし、設定を行いました。

```sh
npm install -D tailwindcss
npx tailwindcss init
```

`tailwind.config.js`を以下のように設定します。

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

`src/index.css`に以下を追加します。

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

### 3. 電卓コンポーネントの作成

`src/components/MainComponent.js`に電卓コンポーネントを作成します。

```javascript
"use client";
import React from "react";

function MainComponent() {
  const [display, setDisplay] = React.useState("0");
  const [currentValue, setCurrentValue] = React.useState("");
  const [previousValue, setPreviousValue] = React.useState("");
  const [operation, setOperation] = React.useState(null);

  const handleNumber = (num) => {
    if (display === "0" || operation) {
      setDisplay(num);
      setCurrentValue(num);
    } else {
      setDisplay((prevDisplay) => prevDisplay + num);
      setCurrentValue((prevValue) => prevValue + num);
    }
  };

  const handleOperation = (op) => {
    if (currentValue) {
      setPreviousValue(currentValue);
      setOperation(op);
      setCurrentValue("");
    }
  };

  const handleEqual = () => {
    if (previousValue && currentValue && operation) {
      const prev = parseFloat(previousValue);
      const curr = parseFloat(currentValue);
      const operations = {
        "+": (a, b) => a + b,
        "-": (a, b) => a - b,
        "*": (a, b) => a * b,
        "/": (a, b) => a / b,
      };
      const result = operations[operation](prev, curr);
      setDisplay(result.toString());
      setCurrentValue(result.toString());
      setPreviousValue("");
      setOperation(null);
    }
  };

  const handleClear = () => {
    setDisplay("0");
    setCurrentValue("");
    setPreviousValue("");
    setOperation(null);
  };

  const renderButton = (btn) => {
    const isOperation = ["+", "-", "*", "/"].includes(btn);
    const isEqual = btn === "=";
    const onClick = isOperation
      ? () => handleOperation(btn)
      : isEqual
      ? handleEqual
      : () => handleNumber(btn);

    let buttonClass =
      "bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-600 hover:to-purple-700 text-white font-bold py-4 px-6 rounded-full shadow-lg transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-purple-400 text-2xl";

    if (isOperation || isEqual) {
      buttonClass =
        "bg-gradient-to-r from-pink-500 to-red-600 hover:from-pink-600 hover:to-red-700 text-white font-bold py-4 px-6 rounded-full shadow-lg transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-red-400 text-2xl";
    }

    return (
      <button key={btn} className={buttonClass} onClick={onClick}>
        {btn}
      </button>
    );
  };

  return (
    <div className="flex flex-col items-center justify-center min-h-screen bg-gradient-to-r from-purple-400 via-pink-500 to-red-500 font-roboto p-4">
      <div className="bg-white bg-opacity-20 backdrop-filter backdrop-blur-lg p-8 rounded-2xl shadow-2xl w-full max-w-md">
        <div className="bg-gray-800 p-4 mb-6 rounded-xl">
          <p className="text-right text-5xl text-white overflow-x-auto whitespace-nowrap">
            {display}
          </p>
        </div>
        <div className="grid grid-cols-4 gap-4">
          {[
            "7",
            "8",
            "9",
            "/",
            "4",
            "5",
            "6",
            "*",
            "1",
            "2",
            "3",
            "-",
            "0",
            ".",
            "=",
            "+",
          ].map(renderButton)}
          <button
            className="col-span-4 bg-gradient-to-r from-yellow-400 to-orange-500 hover:from-yellow-500 hover:to-orange-600 text-white font-bold py-4 px-6 rounded-full shadow-lg transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-orange-400 text-2xl"
            onClick={handleClear}
          >
            Clear
          </button>
        </div>
      </div>
    </div>
  );
}

export default MainComponent;
```

### 4. `App.js`の修正

`src/App.js`を以下のように修正します。

```javascript
import React from 'react';
import './App.css';
import './index.css';
import MainComponent from './components/MainComponent';

function App() {
  return (
    <div className="App">
      <MainComponent />
    </div>
  );
}

export default App;
```

### GitHubへのアップロード

次に、プロジェクトをGitHubにアップロードします。

```sh
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/<your-username>/dentaku.git
git branch -M main
git push -u origin main
```

### Vercelへのデプロイ

Vercelにデプロイする手順は以下の通りです。

1. **Vercel CLIのインストール**

   ```sh
   npm install -g vercel
   ```

2. **Vercelにログイン**

   ```sh
   vercel login
   ```

3. **プロジェクトのデプロイ**

   ```sh
   vercel
   ```

### まとめ

以上の手順で、Reactを使ったモダンな電卓アプリケーション「Dentaku」を開発し、Vercelにデプロイすることができました。興味のある方はぜひ[こちら](https://dentaku-kappa.vercel.app/)からアプリケーションをお試しください。

ご質問やフィードバックがあれば、コメント欄でお知らせください。最後まで読んでいただき、ありがとうございました！

以下は、「Dentaku」電卓アプリケーションのユーザーポリシーのドラフトです。

---

# Dentaku ユーザーポリシー

## はじめに

このユーザーポリシーは、Dentaku電卓アプリケーション（以下「本アプリ」）の利用に関するガイドラインを提供するものです。本アプリを利用することで、本ポリシーの内容に同意したものとみなされます。本アプリの提供者（以下「当社」）は、本ポリシーを随時変更することができます。変更があった場合は、最新のポリシーを本アプリまたは当社のウェブサイトで公開します。

## 1. 利用規約

### 1.1. 本アプリの利用
- 本アプリは、無料で提供される計算機能をユーザーに提供します。
- 本アプリの利用にあたり、ユーザーは本ポリシーを遵守するものとします。

### 1.2. 禁止事項
- 本アプリの機能を悪用すること。
- 他のユーザーまたは第三者に損害を与える行為。
- 本アプリの正常な運営を妨げる行為。
- 法令または公序良俗に反する行為。

## 2. プライバシー

### 2.1. 収集情報
- 本アプリは、個人情報を収集しません。
- ユーザーの利用状況や設定などの情報は、アプリのパフォーマンス改善のために匿名で収集される場合があります。

### 2.2. クッキーの使用
- 本アプリはクッキーを使用しません。

## 3. 免責事項

### 3.1. サービスの提供
- 当社は、本アプリの内容および提供するサービスが正確であるよう努めますが、その完全性、正確性、信頼性を保証するものではありません。
- 当社は、本アプリの利用に関連して生じたいかなる損害についても、一切責任を負いません。

### 3.2. サービスの変更
- 当社は、本アプリの内容や機能を予告なく変更、追加、または削除することがあります。

## 4. 知的財産権

- 本アプリに関するすべてのコンテンツ、デザイン、ロゴ、トレードマーク、その他の知的財産は、当社またはそのライセンサーに帰属します。
- ユーザーは、当社の事前の書面による承諾なしに、これらのコンテンツを複製、転用、配布、公開することはできません。

## 5. お問い合わせ

- 本ポリシーに関するお問い合わせは、以下の連絡先までお願いいたします。

  **連絡先**: [お問い合わせフォームまたはメールアドレス]

## 6. 最終条項

- 本ポリシーは、2024年7月29日から適用されます。
- 本ポリシーの変更があった場合、変更後のポリシーは本アプリまたは当社のウェブサイトで公開されます。