Reactアプリ100本ノックを実践する 〜02 Counter〜

# はじめに
こちらの記事は、@Sicut_studyさんがアップしている【Reactアプリ100本ノック】シリーズに相乗りし、アウトプットを行うための記事になります。
- 実装ルールや成果物の達成条件は元記事に従うものとします。
- 元記事との差別点として、具体的に自分がどんな実装を行ったのか（と必要に応じて解説）を記載します。

@Sicut_studyさんのノック100本についていき、Reactを100日間学ぶのが目標です。

今回の元記事はこちら

https://qiita.com/Sicut_study/items/82059f9cbb5b2996e5b3

# 前回の記事

https://qiita.com/jinto/items/2e0c915f8fecc8cc3681



# 問題
カウンターを作成する

## ルール
**元記事より引用**
- 主要なライブラリやフレームワークはReactである必要がありますが、その他のツールやライブラリ（例: Redux, Next.js, Styled Componentsなど）を組み合わせて使用することは自由
- TypeScriptを利用する

## 達成条件
**元記事より引用**
1. 表示領域: 数字を表示するエリアが存在する。
2. インクリメントボタン: このボタンをクリックすると、表示されている数字が 1 増える。
3. デクリメントボタン: このボタンをクリックすると、表示されている数字が 1 減る。
4. 初期表示: アプリを起動した際の数字は 0 である。
5. ステート管理: React の useState や useReducer を使って、カウントの数字を管理する。

# 実装

前回のアプリをそのまま編集し、`App.tsx`に実装していきます。

## useStateを使う場合

```typescript:src/App.tsx
/** @jsxImportSource @emotion/react */
import { useState } from "react";
import { css } from "@emotion/react";

const App = () => {
  // カウンターの状態を宣言
  const [count, setCount] = useState(0);

  const counterStyle = css`
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    height: 100vh;
    text-align: center;
    background-color: #282c34;
    color: white;
    font-size: 2rem;
  `;

  const buttonStyle = css`
    padding: 10px 20px;
    margin: 5px;
    font-size: 1rem;
    cursor: pointer;
  `;

  return (
    <div css={counterStyle}>
      <p>{count}</p>
      <button css={buttonStyle} onClick={() => setCount(count + 1)}>
        インクリメント
      </button>
      <button css={buttonStyle} onClick={() => setCount(count - 1)}>
        デクリメント
      </button>
    </div>
  );
};

export default App;
```

## useReducerを使う場合

```typescript:src/App.tsx
/** @jsxImportSource @emotion/react */
import { useReducer } from "react";
import { css } from "@emotion/react";

// Stateの型を定義
type State = {
  count: number;
};

// Actionの型を定義
type Action = { type: "increment" } | { type: "decrement" };

// 初期状態
const initialState: State = { count: 0 };

// リデューサー関数
function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

const App = () => {
  // カウンターの状態を宣言
  const [state, dispatch] = useReducer(reducer, initialState);

  const counterStyle = css`
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    height: 100vh;
    text-align: center;
    background-color: #282c34;
    color: white;
    font-size: 2rem;
  `;

  const buttonStyle = css`
    padding: 10px 20px;
    margin: 5px;
    font-size: 1rem;
    cursor: pointer;
  `;

  return (
    <div css={counterStyle}>
      <p>{state.count}</p>
      <button css={buttonStyle} onClick={() => dispatch({ type: "increment" })}>
        インクリメント
      </button>
      <button css={buttonStyle} onClick={() => dispatch({ type: "decrement" })}>
        デクリメント
      </button>
    </div>
  );
};

export default App;
```

# 完成
デザインはまだまだ改善の余地がありますが、要件を満たしているのでこちらで完成。
カウントはきちんと機能します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267522/7d21635d-1b61-7c6d-36d0-ed91d43dc658.png)

# 最後に
Reactアプリ100本ノックを100回分完走するつもりです。
応援してくれる方はぜひフォローいただけると嬉しいです。
いいね、ストックもお待ちしております。

ではまた。

# 次回の記事

https://qiita.com/jinto/items/d5b525ba5a1c27391ea1