商品に「好き」ボタンを追加してみましょう。押された回数が表示できるとよいですね。
src/app/items/[id]/like.tsx
に、下記のファイルを作成します。これが「好き」ボタンです。
"use client";
import { useState } from "react";
const Like = () => {
const [count, setCount] = useState(0);
return (
<div className="flex items-center gap-2">
<button
className="bg-blue-500 text-white px-4 py-2 rounded-md"
onClick={() => setCount(count + 1)}
>
好き
</button>
<span className="text-gray-600">{count}</span>
</div>
);
};
export default Like;
そしてこの「好き」ボタンを商品詳細ページ(app/items/[id]/page.tsx
)に追加します。
import items from "../../../data/items.json";
import Like from "./like";
type Props = {
params: {
id: string;
};
};
export default async function ItemDetail(props: Props) {
const item = items.find((item) => item.id === parseInt(props.params.id));
if (!item) {
return (
<main>
<h1>商品が見つかりませんでした</h1>
</main>
);
}
return (
<main className="container mx-auto px-4 py-8">
<a href="/" className="inline-block m-4 text-blue-600 hover:text-blue-800">
← 商品一覧に戻る
</a>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<img src={item.image} alt={item.name} className="w-full rounded-lg shadow-lg" />
</div>
<div>
<h1 className="text-3xl font-bold m-1">{item.name}</h1>
<p className="text-gray-600 m-8">{item.description}</p>
<div className="bg-blue-100 m-4 p-6 rounded-lg ">
<p className="text-3xl font-bold text-blue-600">{item.price.toLocaleString()}円</p>
<p className="text-gray-600 m-2">カテゴリー: {item.category}</p>
</div>
<Like /> {/* 追加 */}
</div>
</div>
</main>
);
}
これで「好き」ボタンを押すとカウントが増えるようになりました!
use client
は、このファイルがブラウザで実行されることを示します。いままではuse client
をつけていなかったので、サーバーで実行されていました。ブラウザで実行するようにすると、「ボタンを押した」などのユーザーの操作を感知できるようになります。ブラウザで実行するのとサーバーで実行するのでは様々な違いがあるのですが、ここではuse client
をつけるとユーザーの操作を感知できるようになるということを覚えておけばOKです。
useState
は、Reactの状態管理をするための関数です。Reactのコンポーネントはなにか変化があると再度画面がレンダリングされます。useState
は、その変化する値を作り出すための関数です。二つの値、count
とsetCount
を返します。count
は現在の値で、setCount
は値を更新するための関数です。
onClick
に関数を渡すと、ボタンがクリックされたときにその関数が実行されます。ここではボタンが押されたら「好き」のカウントを増やしたいので、setCount
を呼び出してcount
の値を更新しています。
10回目の「好き」を祝いましょう!下記のコンポーネントは表示されるとめでたい画面になるように作られています。src/app/items/[id]/like.tsx
に下記のコンポーネントを追加して、10回目の「好き」で表示されるように実装を変更してみましょう。出したり消したりするのは、count
を条件に使って、このCelebration
コンポーネントの表示・非表示を切りかえればよさそうです。
const Celebration = () => {
const emojiCount = 50;
const fontSize = 100;
return (
<div className="fixed inset-0 pointer-events-none">
<>
<style jsx global>{`
@keyframes fall {
0% {
transform: translateY(-100vh) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
`}</style>
{Array.from({ length: emojiCount }).map((_, i) => (
<div
key={i}
className="absolute"
style={{
left: `${Math.random() * 100}%`,
top: `${Math.random() * 100}%`,
animation: `fall ${2 + Math.random() * 3}s linear forwards`,
fontSize: `${100 + fontSize * Math.random()}px`,
}}
>
☺️
</div>
))}
</>
</div>
);
};
ヒント1: JavaScriptでは %
で余りを計算できます。9 % 10
は9
で、10 % 10
は0
、11 % 10
は1
です。
ヒント2: { showCelebration ? <Celebration /> : null }
とすると、条件(ここではshowCelebration
)によって表示する内容を切り替えることができます。
Celebration
ではCSSのアニメーションを使っています。詳細な説明は省略しますが、@keyframes
でfall
というアニメーションを定義し、animation
でアニメーションを適用しています。
emojiCount
、fontSize
を変更すると、表示される絵文字の数や大きさを変更できます。また☺
を変更すれば出力される絵文字も変更できます。️お好きな量・お好きな大きさで、お好きな絵文字をたくさん出してみてください。