🏋️

【実践】React 100本ノック No.2:Counter

2024/06/24に公開

はじめに

こんにちは!@haganenoubik(アライ リョータ)です。

現在、ReactとTypeScriptを学習中です。
今回は、シンプルなカウンターアプリを作成することで、Reactの基本的な使い方を学びます。

前回に引き続き、アウトプット主体でReactへの理解度を深めるために、下記のQiita記事シリーズを参考に、課題のミニアプリを作成していきます。

https://qiita.com/Sicut_study/items/3c5cd798313854a471a0

前回はこちら ↓
https://zenn.dev/haganenoubik/articles/a7d896f58647fe

使用環境

手軽に環境構築できるため、基本的にはStackblitzを使用していく予定。

Stackblitz

課題

  • カウンターの作成
成果物

こちらで実際に動作するカウンターアプリを確認できます。
https://stackblitz.com/edit/vitejs-vite-5mvehs

達成条件

  • カウンターの数値表示がされている(初期表示は0)
  • インクリメントボタンがある(クリックするとカウンターの数値が1増加する)
  • デクリメントボタンがある(クリックするとカウンターの数値が1減少する)
  • useStateやuseReducerを使用してカウントの数字を管理する
  • スタイリング等は自由

技術スタック

  • Vite
  • React
  • TypeScript
  • Styled Components
  • MUI(Material UI)

実装の大まかな流れ

前提
  • Stackblitzで「React(TypeScript)」を選択して新規プロジェクト作成
  • プロジェクト作成辞にデフォルトで設定されているCSS等は一旦削除して開始
  • Counterコンポーネントの作成
  • MUIを用いてカウンターのデザインを作成
  • Styled Componentsのインストール
  • カウンターを画面中央に配置
  • useStateで初期値を0に指定、状態としてcount・更新関数としてsetCountを定義
  • カウンター表示部分にstateであるcountを配置
  • ボタンにonClickイベントを指定し、クリック時に数値を増加・減少させる関数を定義する

完成 🙌

コード
App.tsx
import './App.css'
import { Counter } from './components/Counter'

function App() {
  return (
    <>
      <Counter />
    </>
  )
}

export default App
components/Counter.tsx
import  { FC, useState } from 'react';
import { Button, ButtonGroup } from '@mui/material';
import styled from 'styled-components';

export const Counter: FC = () => {

  const [count, setCount] = useState<number>(0);

  const onClickIncrement = () => {
    // 関数形式で状態を更新
    setCount(prevCount => prevCount + 1)
  };
  const onClickDecrement = () => {
    setCount(prevCount => prevCount - 1)
  };

  return (
    <SContainer>
      <h4>Counter</h4>
      <h1>{count}</h1>
      <ButtonGroup>
        <Button onClick={onClickIncrement}>+</Button>
        <Button onClick={onClickDecrement} color="secondary">-</Button>
      </ButtonGroup>
    </SContainer>
  );
};

const SContainer = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  height: 100vh;
`;
useStateのアンチパターン
components/Counter.tsx
const onClickIncrement = () => {
  // countの値を直接引数として使用
  setCount(count + 1);
};

const onClickDecrement = () => {
  setCount(count - 1);
};

useStateを使用して状態を更新する際
👍 更新関数に関数を渡す(最新の状態を引数として渡してくれる)

  • prevCount:直前のcountの値
    -> 連続した状態更新を、確実に最新のstateを基に行われることが保証される

👎 更新関数に直接現在のstateを使用する

  • stateの更新が非同期で行われる
    -> 連続した更新が正しく反映されない可能性がある

例:素早く2回クリックした時
関数形式を使用する場合

  • 最初のクリック: countが0から1に更新
  • 次のクリック: countが1から2に更新

関数形式を使用しない場合

  • 最初のクリック: countが0から1に更新
  • 次のクリック: countが0のまま再度1に更新(前の更新が反映されていないため)

👮 関数形式にしな場合、正常に更新されない可能性があるため、一見動作に問題がなさそうでもバグの原因を内包している

総括

MUIはReactの基礎学習を終えていれば、コンポーネント形式で直感的にスタイリングできるので手軽だなと感じました。
ただ、プロジェクトの規模が大きい場合だと、UIライブラリを使用する弊害が出てくるのかなと感じたので、導入に際しては拡張性も踏まえて検討する必要があるかも。
useReducerはまだ使ったことがない(使い方もわかってない)ので、追々学習していきたいですね。

おわりに

他の学習等と並行しつつなので、更新は不定期になるかと思いますが、コードの記法やファイル構造で、ベターな方法があればアドバイスいただけるとありがたいです!

それではまた次回!👋

GitHubで編集を提案

Discussion