レッスン 5

状態管理とイベントハンドリング

ReacTouch
React Logo
LESSON 5|

状態管理とイベントハンドリング

このレッスンでは、LESSON3で作った商品カードに動的な機能を追加していきます。 お気に入りボタンや商品追加ボタンを作ることで、基本的な状態管理を学んでいきましょう。
Step 1

お気に入りボタンの状態管理を実装しよう!

商品にお気に入り機能を追加しましょう。 useStateを使って、お気に入りの状態(true/false)を管理します。 手順: 1. React Hookの `useState` をインポート 2. お気に入りの状態変数を定義(初期値:false) 3. お気に入りボタンを追加 4. ボタンクリックで状態を切り替える 5. 状態に応じてハートアイコンを変更 実装のポイント: - boolean型の状態管理を理解する - イベントハンドラーの実装方法を学ぶ - 状態に応じた条件分岐表示を実装する

ProductCard.jsx

import ProductImage from './ProductImage'
import ProductInfo from './ProductInfo'

const ProductCard = ({ product }) => {
  return (
    <div className="product-card">
      <ProductImage product={product} />
      <ProductInfo product={product} />
    </div>
  )
}

export default ProductCard

ProductInfo.jsx

const ProductInfo = ({ product }) => {
  const getStarRating = (rating) => {
    const fullStars = Math.floor(rating);
    const hasHalfStar = rating % 1 !== 0;
    return '★'.repeat(fullStars) + (hasHalfStar ? '☆' : '');
  }

  const discountPercent = Math.round(product.discountRate * 100);
  const discountedPrice = product.price * (1 - product.discountRate);

  return (
    <div className="product-info">
      <p className="brand-name">{product.brand}</p>
      <h1>{product.name}</h1>
      <div className="price-container">
        <p className="discount-price">¥{discountedPrice.toLocaleString()}</p>
        <p className="price">¥{product.price.toLocaleString()}</p>
        <span className="discount-badge">{discountPercent}%OFF</span>
      </div>
      <p className="rating">
        {getStarRating(product.rating)}
        <span className="review-count">({product.reviewCount})</span>
      </p>
      {/* TODO: ここにお気に入りボタンを追加 */}
    </div>
  );
}

export default ProductInfo
React Hookのインポート
import { useState } from 'react'
お気に入り状態の定義
const [isFavorite, setIsFavorite] = useState(false);
お気に入りトグル関数
const toggleFavorite = () => {
  setIsFavorite(!isFavorite);
};
お気に入りボタンのJSX
<button 
  className={isFavorite ? "favorite-button active" : "favorite-button"}
  onClick={toggleFavorite}
>
  <span className="heart-icon">{isFavorite ? "♥" : "♡"}</span>
  お気に入り
</button>
Step 2

商品数量カウンター機能を実装しよう!

商品の購入数量を管理するカウンター機能を実装しましょう。 + と - のボタンで数量を増減できるようにします。 手順: 1. 数量を管理する状態変数を追加(初期値:1) 2. 数量を増やす・減らす関数を実装 3. 数量が0以下にならないよう制御 4. カウンターUIを追加 5. 数量に応じて合計価格を動的に表示 実装のポイント: - number型の状態管理を理解する - 複数の状態変数を同一コンポーネントで管理 - 条件分岐による制限の実装 - 動的な価格計算の実装

ProductInfo.jsx

import { useState } from 'react'

const ProductInfo = ({ product }) => {
  const [isFavorite, setIsFavorite] = useState(false);
  
  const getStarRating = (rating) => {
    const fullStars = Math.floor(rating);
    const hasHalfStar = rating % 1 !== 0;
    return '★'.repeat(fullStars) + (hasHalfStar ? '☆' : '');
  }

  const toggleFavorite = () => {
    setIsFavorite(!isFavorite);
  };

  const discountPercent = Math.round(product.discountRate * 100);
  const discountedPrice = product.price * (1 - product.discountRate);

  return (
    <div className="product-info">
      <p className="brand-name">{product.brand}</p>
      <h1>{product.name}</h1>
      <div className="price-container">
        <p className="discount-price">¥{discountedPrice.toLocaleString()}</p>
        <p className="price">¥{product.price.toLocaleString()}</p>
        <span className="discount-badge">{discountPercent}%OFF</span>
      </div>
      <p className="rating">
        {getStarRating(product.rating)}
        <span className="review-count">({product.reviewCount})</span>
      </p>
      <button 
        className={isFavorite ? "favorite-button active" : "favorite-button"}
        onClick={toggleFavorite}
      >
        <span className="heart-icon">{isFavorite ? "♥" : "♡"}</span>
        お気に入り
      </button>
      {/* TODO: ここに数量カウンターを追加 */}
    </div>
  );
}

export default ProductInfo
数量状態の定義
const [quantity, setQuantity] = useState(1);
数量変更関数
const increaseQuantity = () => {
  setQuantity(quantity + 1);
};

const decreaseQuantity = () => {
  if (quantity > 1) {
    setQuantity(quantity - 1);
  }
};
カウンターボタンのJSX
<div className="quantity-controls">
  <h3>数量選択</h3>
  <div className="quantity-counter">
    <button 
      className="quantity-btn"
      onClick={decreaseQuantity}
      disabled={quantity <= 1}
    >
      -
    </button>
    <span className="quantity-display">{quantity}</span>
    <button 
      className="quantity-btn"
      onClick={increaseQuantity}
    >
      +
    </button>
  </div>
  <p className="total-price">
    合計: ¥{(discountedPrice * quantity).toLocaleString()}
  </p>
</div>

🎉 お疲れ様です!全てのステップを完了しました!

FILES
Loading Monaco Editor...