Click files to view code →
Create an interactive like button component similar to those found in social media platforms. The button should toggle between liked and unliked states, display a count of likes, and provide visual feedback with animations.
[!TIP] Goal
Use React's
useState[!IMPORTANT] Requirements
Optional:
Key Topics:
Plan of Action:
LikeButtonisLikedlikeCountimport React, { useState } from 'react';
import './LikeButton.css';
function LikeButton({
initialLikes = 0,
initialIsLiked = false,
onLikeChange
}) {
const [isLiked, setIsLiked] = useState(initialIsLiked);
const [likeCount, setLikeCount] = useState(initialLikes);
const [isAnimating, setIsAnimating] = useState(false);
const handleLike = () => {
// Toggle liked state
const newLikedState = !isLiked;
setIsLiked(newLikedState);
// Update count
if (newLikedState) {
setLikeCount(likeCount + 1);
} else {
setLikeCount(likeCount - 1);
}
// Trigger animation
setIsAnimating(true);
setTimeout(() => setIsAnimating(false), 300);
// Notify parent component if callback provided
if (onLikeChange) {
onLikeChange(newLikedState, newLikedState ? likeCount + 1 : likeCount - 1);
}
};
return (
<div className="like-button-container">
<button
className={`like-button ${isLiked ? 'liked' : ''} ${isAnimating ? 'animating' : ''}`}
onClick={handleLike}
aria-label={isLiked ? 'Unlike' : 'Like'}
aria-pressed={isLiked}
>
<span className="heart-icon">
{isLiked ? '❤️' : '🤍'}
</span>
<span className="like-count">
{likeCount}
</span>
</button>
</div>
// ...CSS Styling (LikeButton.css):
.like-button-container {
display: inline-block;
padding: 1rem;
}
.like-button {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.25rem;
font-size: 1.125rem;
background-color: #fff;
border: 2px solid #e0e0e0;
border-radius: 25px;
cursor: pointer;
transition: all 0.2s ease;
font-family: Arial, sans-serif;
outline: none;
}
.like-button:hover {
border-color: #ff6b6b;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(255, 107, 107, 0.2);
}
.like-button:focus {
box-shadow: 0 0 0 3px rgba(255, 107, 107, 0.3);
}
.like-button:active {
transform: translateY(0);
}
.like-button.liked {
background-color: #ffe0e0;
border-color: #ff6b6b;
}
.heart-icon {
font-size: 1.5rem;
transition: transform 0.2s ease;
display: inline-block;
}
.like-button.animating .heart-icon {
animation: heartPop 0.3s ease;
}
@keyframes heartPop {
// ...Usage Example:
import React, { useState } from 'react';
import LikeButton from './LikeButton';
function PostCard() {
const handleLikeChange = (isLiked, newCount) => {
console.log(`Post is ${isLiked ? 'liked' : 'unliked'}. Total likes: ${newCount}`);
// Here you could make an API call to update the server
};
return (
<div className="post-card">
<h3>Amazing Post Title</h3>
<p>This is the post content...</p>
<LikeButton
initialLikes={42}
initialIsLiked={false}
onLikeChange={handleLikeChange}
/>
</div>
);
}Best Practices:
Common Pitfalls:
Enhancements:
Advanced Version with API Integration:
import React, { useState } from 'react';
import './LikeButton.css';
function LikeButton({ postId, initialLikes = 0, initialIsLiked = false }) {
const [isLiked, setIsLiked] = useState(initialIsLiked);
const [likeCount, setLikeCount] = useState(initialLikes);
const [isLoading, setIsLoading] = useState(false);
const [isAnimating, setIsAnimating] = useState(false);
const handleLike = async () => {
// Optimistic update
const newLikedState = !isLiked;
const newCount = newLikedState ? likeCount + 1 : likeCount - 1;
setIsLiked(newLikedState);
setLikeCount(newCount);
setIsAnimating(true);
setTimeout(() => setIsAnimating(false), 300);
setIsLoading(true);
try {
// Make API call
const response = await fetch(`/api/posts/${postId}/like`, {
method: newLikedState ? 'POST' : 'DELETE',
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) {
throw new Error('Failed to update like');
}
const data = await response.json();
// Update with server count if different
setLikeCount(data.likeCount);
} catch (error) {
// Rollback on error
console.error('Error updating like:', error);
setIsLiked(!newLikedState);
setLikeCount(likeCount);
// Show error message to user
} finally {
setIsLoading(false);
}
};
return (
<button
className={`like-button ${isLiked ? 'liked' : ''} ${isAnimating ? 'animating' : ''}`}
onClick={handleLike}
// ...Version with Multiple Reactions:
function ReactionButton() {
const [selectedReaction, setSelectedReaction] = useState(null);
const reactions = ['❤️', '👍', '😂', '😮', '😢', '😡'];
return (
<div className="reaction-container">
{reactions.map((emoji, index) => (
<button
key={index}
className={`reaction ${selectedReaction === emoji ? 'selected' : ''}`}
onClick={() => setSelectedReaction(emoji)}
>
{emoji}
</button>
))}
</div>
);
}Testing Considerations:
Real-World Use Cases:
This like button component demonstrates important concepts in interactive UI development and can be adapted for various social features.
No files open
Click a file in the explorer to view