React Counter App
Build an interactive Counter App in React demonstrating component state management with useState, event handling, conditional styling, and reset functionalities.
The Problem
Build an interactive Counter App in React demonstrating component state management with useState, event handling, conditional styling, and reset functionalities.
Real-World Use Case
Build an interactive Counter App in React demonstrating component state management with useState, event handling, conditional styling, and reset functionalities.
Technology Stack
Basic knowledge of HTML and CSS
Prerequisite
Familiarity with JSX syntax
Prerequisite
Understanding of React functional components
Prerequisite
Architecture & Design
Folder Structure
counter_app/
├── src/
│ ├── App.jsx
│ ├── index.css
│ └── main.jsx
└── package.jsonStep-by-Step Implementation
Import useState hook from React.
### Step 1: Project Setup Initialize a Vite React project. Open `src/App.jsx` and clear default boilerplate.
import { useState } from 'react';
export default function CounterApp() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const increment = () => setCount(c => c + step);
const decrement = () => setCount(c => c - step);
const reset = () => { setCount(0); setStep(1); };
return (
<div className="max-w-md mx-auto my-10 p-8 bg-white rounded-3xl shadow-sm border border-slate-200 text-center">
<h1 className="text-2xl font-bold text-slate-900 mb-2">React Counter App</h1>
<p className="text-xs text-slate-500 mb-6">Mastering useState and Event Handlers</p>
<div className="py-8 bg-slate-50 rounded-2xl mb-6 border border-slate-100">
<span className={`text-5xl font-extrabold ${count > 0 ? 'text-green-600' : count < 0 ? 'text-red-600' : 'text-slate-800'}`}>
{count}
</span>
</div>
<div className="mb-6 flex items-center justify-center gap-2">
<label className="text-xs font-semibold text-slate-600">Step Size:</label>
<input
type="number"
value={step}
onChange={(e) => setStep(Math.max(1, parseInt(e.target.value) || 1))}
className="w-16 p-1 text-center border border-slate-200 rounded-lg text-xs"
min="1"
/>
</div>
<div className="grid grid-cols-3 gap-3">
<button
onClick={decrement}
className="py-3 bg-rose-500 hover:bg-rose-600 text-white font-bold rounded-xl shadow-xs transition"
>
-{step}
</button>
<button
onClick={reset}
className="py-3 bg-slate-600 hover:bg-slate-700 text-white font-bold rounded-xl shadow-xs transition"
>
Reset
</button>
<button
onClick={increment}
className="py-3 bg-emerald-500 hover:bg-emerald-600 text-white font-bold rounded-xl shadow-xs transition"
>
+{step}
</button>
</div>
</div>
);
}Code Explanation
Implementation step
Initialize count state variable to 0.
### Step 2: State & Handlers Implementation Define state and update functions. ```jsx import { useState } from 'react'; export default function App() { const [count, setCount] = useState(0); const increment = () => setCount(prev => prev + 1); const decrement = () => setCount(prev => prev - 1); const reset = () => setCount(0); ```
import { useState } from 'react';
export default function CounterApp() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const increment = () => setCount(c => c + step);
const decrement = () => setCount(c => c - step);
const reset = () => { setCount(0); setStep(1); };
return (
<div className="max-w-md mx-auto my-10 p-8 bg-white rounded-3xl shadow-sm border border-slate-200 text-center">
<h1 className="text-2xl font-bold text-slate-900 mb-2">React Counter App</h1>
<p className="text-xs text-slate-500 mb-6">Mastering useState and Event Handlers</p>
<div className="py-8 bg-slate-50 rounded-2xl mb-6 border border-slate-100">
<span className={`text-5xl font-extrabold ${count > 0 ? 'text-green-600' : count < 0 ? 'text-red-600' : 'text-slate-800'}`}>
{count}
</span>
</div>
<div className="mb-6 flex items-center justify-center gap-2">
<label className="text-xs font-semibold text-slate-600">Step Size:</label>
<input
type="number"
value={step}
onChange={(e) => setStep(Math.max(1, parseInt(e.target.value) || 1))}
className="w-16 p-1 text-center border border-slate-200 rounded-lg text-xs"
min="1"
/>
</div>
<div className="grid grid-cols-3 gap-3">
<button
onClick={decrement}
className="py-3 bg-rose-500 hover:bg-rose-600 text-white font-bold rounded-xl shadow-xs transition"
>
-{step}
</button>
<button
onClick={reset}
className="py-3 bg-slate-600 hover:bg-slate-700 text-white font-bold rounded-xl shadow-xs transition"
>
Reset
</button>
<button
onClick={increment}
className="py-3 bg-emerald-500 hover:bg-emerald-600 text-white font-bold rounded-xl shadow-xs transition"
>
+{step}
</button>
</div>
</div>
);
}Code Explanation
Implementation step
Create increment, decrement, and reset handler functions.
### Step 3: UI Implementation Render buttons and dynamic count display. ```jsx return ( <div className="flex flex-col items-center justify-center p-8"> <h1 className="text-2xl font-bold">React Counter App</h1> <p className="text-4xl font-extrabold my-4">{count}</p> <div className="flex gap-4"> <button onClick={decrement} className="px-4 py-2 bg-red-500 text-white">-</button> <button onClick={reset} className="px-4 py-2 bg-slate-500 text-white">Reset</button> <button onClick={increment} className="px-4 py-2 bg-green-500 text-white">+</button> </div> </div> ); } ```
import { useState } from 'react';
export default function CounterApp() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const increment = () => setCount(c => c + step);
const decrement = () => setCount(c => c - step);
const reset = () => { setCount(0); setStep(1); };
return (
<div className="max-w-md mx-auto my-10 p-8 bg-white rounded-3xl shadow-sm border border-slate-200 text-center">
<h1 className="text-2xl font-bold text-slate-900 mb-2">React Counter App</h1>
<p className="text-xs text-slate-500 mb-6">Mastering useState and Event Handlers</p>
<div className="py-8 bg-slate-50 rounded-2xl mb-6 border border-slate-100">
<span className={`text-5xl font-extrabold ${count > 0 ? 'text-green-600' : count < 0 ? 'text-red-600' : 'text-slate-800'}`}>
{count}
</span>
</div>
<div className="mb-6 flex items-center justify-center gap-2">
<label className="text-xs font-semibold text-slate-600">Step Size:</label>
<input
type="number"
value={step}
onChange={(e) => setStep(Math.max(1, parseInt(e.target.value) || 1))}
className="w-16 p-1 text-center border border-slate-200 rounded-lg text-xs"
min="1"
/>
</div>
<div className="grid grid-cols-3 gap-3">
<button
onClick={decrement}
className="py-3 bg-rose-500 hover:bg-rose-600 text-white font-bold rounded-xl shadow-xs transition"
>
-{step}
</button>
<button
onClick={reset}
className="py-3 bg-slate-600 hover:bg-slate-700 text-white font-bold rounded-xl shadow-xs transition"
>
Reset
</button>
<button
onClick={increment}
className="py-3 bg-emerald-500 hover:bg-emerald-600 text-white font-bold rounded-xl shadow-xs transition"
>
+{step}
</button>
</div>
</div>
);
}Code Explanation
Implementation step
Attach handlers to button onClick events.
### Step 4: Edge Cases Prevent count from dropping below a specific threshold if required, or ensure styling updates smoothly.
import { useState } from 'react';
export default function CounterApp() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const increment = () => setCount(c => c + step);
const decrement = () => setCount(c => c - step);
const reset = () => { setCount(0); setStep(1); };
return (
<div className="max-w-md mx-auto my-10 p-8 bg-white rounded-3xl shadow-sm border border-slate-200 text-center">
<h1 className="text-2xl font-bold text-slate-900 mb-2">React Counter App</h1>
<p className="text-xs text-slate-500 mb-6">Mastering useState and Event Handlers</p>
<div className="py-8 bg-slate-50 rounded-2xl mb-6 border border-slate-100">
<span className={`text-5xl font-extrabold ${count > 0 ? 'text-green-600' : count < 0 ? 'text-red-600' : 'text-slate-800'}`}>
{count}
</span>
</div>
<div className="mb-6 flex items-center justify-center gap-2">
<label className="text-xs font-semibold text-slate-600">Step Size:</label>
<input
type="number"
value={step}
onChange={(e) => setStep(Math.max(1, parseInt(e.target.value) || 1))}
className="w-16 p-1 text-center border border-slate-200 rounded-lg text-xs"
min="1"
/>
</div>
<div className="grid grid-cols-3 gap-3">
<button
onClick={decrement}
className="py-3 bg-rose-500 hover:bg-rose-600 text-white font-bold rounded-xl shadow-xs transition"
>
-{step}
</button>
<button
onClick={reset}
className="py-3 bg-slate-600 hover:bg-slate-700 text-white font-bold rounded-xl shadow-xs transition"
>
Reset
</button>
<button
onClick={increment}
className="py-3 bg-emerald-500 hover:bg-emerald-600 text-white font-bold rounded-xl shadow-xs transition"
>
+{step}
</button>
</div>
</div>
);
}Code Explanation
Implementation step
Apply dynamic CSS classes based on whether count is positive, negative, or zero.
### Step 4: Edge Cases Prevent count from dropping below a specific threshold if required, or ensure styling updates smoothly.
import { useState } from 'react';
export default function CounterApp() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const increment = () => setCount(c => c + step);
const decrement = () => setCount(c => c - step);
const reset = () => { setCount(0); setStep(1); };
return (
<div className="max-w-md mx-auto my-10 p-8 bg-white rounded-3xl shadow-sm border border-slate-200 text-center">
<h1 className="text-2xl font-bold text-slate-900 mb-2">React Counter App</h1>
<p className="text-xs text-slate-500 mb-6">Mastering useState and Event Handlers</p>
<div className="py-8 bg-slate-50 rounded-2xl mb-6 border border-slate-100">
<span className={`text-5xl font-extrabold ${count > 0 ? 'text-green-600' : count < 0 ? 'text-red-600' : 'text-slate-800'}`}>
{count}
</span>
</div>
<div className="mb-6 flex items-center justify-center gap-2">
<label className="text-xs font-semibold text-slate-600">Step Size:</label>
<input
type="number"
value={step}
onChange={(e) => setStep(Math.max(1, parseInt(e.target.value) || 1))}
className="w-16 p-1 text-center border border-slate-200 rounded-lg text-xs"
min="1"
/>
</div>
<div className="grid grid-cols-3 gap-3">
<button
onClick={decrement}
className="py-3 bg-rose-500 hover:bg-rose-600 text-white font-bold rounded-xl shadow-xs transition"
>
-{step}
</button>
<button
onClick={reset}
className="py-3 bg-slate-600 hover:bg-slate-700 text-white font-bold rounded-xl shadow-xs transition"
>
Reset
</button>
<button
onClick={increment}
className="py-3 bg-emerald-500 hover:bg-emerald-600 text-white font-bold rounded-xl shadow-xs transition"
>
+{step}
</button>
</div>
</div>
);
}Code Explanation
Implementation step
Common Errors
Use functional state update setCount(prev => prev + 1).
Provide fallback value parseInt(e.target.value) || 1.
Security & Performance
Click increment button and verify count increases correctly.
Adjust step size to 5 and confirm increment jumps by 5.
Click decrement to reach negative numbers and check red color styling.
Click reset button and verify both count and step return to default.
Add localStorage persistence so count remains upon browser refresh.
Add sound effects upon clicking buttons.
Implement maximum and minimum limits for count.
Interview Questions
Q: Why do we use const [count, setCount]?
A: It destructures the array returned by useState into the current state value and its setter function.
Q: Why not modify count directly (count = count + 1)?
A: Direct mutation does not trigger React component re-rendering. You must use setCount.