T

TechIdea

Ecosystem

Back to react Projects
Beginner Level

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.json

Step-by-Step Implementation

1

Import useState hook from React.

### Step 1: Project Setup Initialize a Vite React project. Open `src/App.jsx` and clear default boilerplate.

react
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

2

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); ```

react
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

3

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> ); } ```

react
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

4

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.

react
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

5

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.

react
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

Stale state closure when clicking rapidly.

Use functional state update setCount(prev => prev + 1).

Step size becomes NaN when input cleared.

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.

Growth Newsletter

Get practical AI tools, SEO tips, and growth guides weekly.

Join creators, students, and businesses scaling with TechIdea.