レッスン 5
商品にお気に入り機能を追加しましょう。 useStateを使って、お気に入りの状態(true/false)を管理します。 手順: 1. React Hookの `useState` をインポート 2. お気に入りの状態変数を定義(初期値:false) 3. お気に入りボタンを追加 4. ボタンクリックで状態を切り替える 5. 状態に応じてハートアイコンを変更 実装のポイント: - boolean型の状態管理を理解する - イベントハンドラーの実装方法を学ぶ - 状態に応じた条件分岐表示を実装する
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 ProductCardconst 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 ProductInfoimport { useState } from 'react'const [isFavorite, setIsFavorite] = useState(false);const toggleFavorite = () => {
setIsFavorite(!isFavorite);
};<button
className={isFavorite ? "favorite-button active" : "favorite-button"}
onClick={toggleFavorite}
>
<span className="heart-icon">{isFavorite ? "♥" : "♡"}</span>
お気に入り
</button>商品の購入数量を管理するカウンター機能を実装しましょう。 + と - のボタンで数量を増減できるようにします。 手順: 1. 数量を管理する状態変数を追加(初期値:1) 2. 数量を増やす・減らす関数を実装 3. 数量が0以下にならないよう制御 4. カウンターUIを追加 5. 数量に応じて合計価格を動的に表示 実装のポイント: - number型の状態管理を理解する - 複数の状態変数を同一コンポーネントで管理 - 条件分岐による制限の実装 - 動的な価格計算の実装
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 ProductInfoconst [quantity, setQuantity] = useState(1);const increaseQuantity = () => {
setQuantity(quantity + 1);
};
const decreaseQuantity = () => {
if (quantity > 1) {
setQuantity(quantity - 1);
}
};<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>🎉 お疲れ様です!全てのステップを完了しました!