Popular Searches
Popular Course Categories
Popular Courses

Counter Application

Counter Application

React JS Practical Projects

Counter Application in React JS

A Counter Application is a beginner-friendly React JS project used to understand state management, event handling, component rendering, and user interaction. It allows users to increase, decrease, and reset a numerical value using buttons. React's useState() Hook is commonly used to store and update the counter value.

Course: JustAcademy React JS Training Course

Course Demo: Register for React JS Course Demo


1. Learning Objectives

After completing this topic, learners will be able to:

  • Understand the concept and purpose of a Counter Application.
  • Create functional components in React JS.
  • Use the useState() Hook to manage counter values.
  • Handle button clicks using event handlers.
  • Increment, decrement, and reset a counter.
  • Understand how state updates trigger component re-rendering.
  • Apply conditional rendering and basic input validation.
  • Build a simple interactive React JS project.

2. What Is a Counter Application?

A Counter Application is a small interactive application that displays a number and allows users to change that number through different actions. In React JS, the displayed number is generally stored in component state.

Example: A counter starts at 0. When the user clicks the Increase button, the value changes to 1. Clicking Increase again changes it to 2. The Decrease button reduces the value, and the Reset button returns it to 0.

Common Counter Operations

Operation Description Example
Increment Increases the current count by one. 0 → 1
Decrement Decreases the current count by one. 5 → 4
Reset Returns the count to its initial value. 8 → 0
Custom Increment Increases the count by a selected amount. 2 → 7 when adding 5
Minimum Limit Prevents the count from going below a defined value. 0 remains 0

3. Why Build a Counter Application in React?

A Counter Application helps beginners understand the fundamental features of React without needing a complex project.

  • State management: Stores the current counter value.
  • Event handling: Responds to user actions such as button clicks.
  • Component-based development: Organizes the interface into reusable components.
  • Dynamic UI updates: Displays the latest value when state changes.
  • Conditional rendering: Displays messages based on the counter value.
  • Practical learning: Builds a foundation for forms, shopping carts, dashboards, and other interactive applications.

4. Prerequisites

Before creating the Counter Application, learners should understand the following concepts:

  • Basic HTML elements such as headings, buttons, and containers.
  • CSS properties for layout, spacing, colors, and typography.
  • JavaScript variables, functions, arrow functions, and event concepts.
  • Basic React components and JSX syntax.
  • Basic understanding of npm and a React development environment.

5. Understanding State in React JS

State is data that a React component remembers between renders. When state changes through its setter function, React schedules a re-render so the interface can display the updated value.

For a counter, the state variable stores the current number, and the setter function updates that number.

Example of useState()

import { useState } from 'react';
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <h1>Count: {count}</h1>
    </div>
  );
}
export default Counter;

Explanation

Code Meaning
import { useState } from 'react'; Imports the React Hook used for state management.
useState(0) Initializes the counter value to 0.
count Contains the current counter value.
setCount Updates the counter state.
{count} Displays the current value in JSX.

Important: Do not change the state variable directly, such as count = count + 1. Use the setter function, such as setCount(count + 1), so React can update the interface correctly.


6. Creating a Counter Application Step by Step

Step 1: Create a React Project

If you do not already have a React project, you can create one using Vite. Make sure Node.js and npm are installed.

npm create vite@latest counter-app -- --template react
cd counter-app
npm install
npm run dev

Run the command shown by Vite in your terminal and open the local URL it provides in your browser.

Step 2: Understand the Project Structure

counter-app/
├── public/
├── src/
│   ├── App.jsx
│   ├── App.css
│   ├── index.css
│   └── main.jsx
├── package.json
└── index.html

File responsibilities:

  • App.jsx contains the Counter Application component.
  • App.css contains styles for the counter interface.
  • index.css contains global styles.
  • main.jsx renders the React application into the page.
  • package.json stores project dependencies and scripts.

Step 3: Write the Counter Component

Replace the content of src/App.jsx with the following code:

import { useState } from 'react';
import './App.css';

function App() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(previousCount => previousCount + 1);
  };

  const decrement = () => {
    setCount(previousCount => previousCount - 1);
  };

  const reset = () => {
    setCount(0);
  };

  return (
    <main className="counter-container">
      <h1>Counter Application</h1>
      <p className="description">
        Manage your counter with simple buttons.
      </p>
      <div className="counter-value" aria-live="polite">
        {count}
      </div>
      <div className="button-group">
        <button onClick={decrement}>Decrease</button>
        <button onClick={reset}>Reset</button>
        <button onClick={increment}>Increase</button>
      </div>
      <p className="status">
        {count > 0
          ? 'The count is positive.'
          : count < 0
          ? 'The count is negative.'
          : 'The count is zero.'}
      </p>
    </main>
  );
}

export default App;

Step 4: Add CSS Styling

Replace the content of src/App.css with the following styles:

.counter-container {
  max-width: 480px;
  margin: 60px auto;
  padding: 32px 24px;
  text-align: center;
  font-family: Arial, sans-serif;
  background: #ffffff;
  border-radius: 16px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.12);
}
.counter-container h1 {
  margin-bottom: 8px;
  color: #1f2937;
}
.description {
  color: #6b7280;
}
.counter-value {
  margin: 28px 0;
  font-size: 64px;
  font-weight: bold;
  color: #2563eb;
}
.button-group {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
}
.button-group button {
  padding: 12px 18px;
  border: none;
  border-radius: 8px;
  background: #2563eb;
  color: #ffffff;
  font-size: 15px;
  cursor: pointer;
}
.button-group button:hover {
  background: #1d4ed8;
}
.button-group button:focus-visible {
  outline: 3px solid #93c5fd;
  outline-offset: 3px;
}
.status {
  margin-top: 22px;
  color: #374151;
}
@media (max-width: 480px) {
  .counter-container {
    margin: 24px 12px;
    padding: 24px 16px;
  }
  .counter-value {
    font-size: 52px;
  }
}

Step 5: Check Global CSS

In src/index.css, you can use the following minimal global styles:

* {
  box-sizing: border-box;
}
body {
  margin: 0;
  min-height: 100vh;
  background: #f3f4f6;
}

Step 6: Run and Test the Application

  1. Start the development server using npm run dev.
  2. Open the local URL displayed in the terminal.
  3. Click Increase and verify that the number increases.
  4. Click Decrease and verify that the number decreases.
  5. Click Reset and verify that the number returns to 0.
  6. Check that the status message changes based on the current value.

7. How the Counter Application Works

The application follows a simple state-update cycle:

User clicks a button
        ↓
React event handler runs
        ↓
State setter updates the count
        ↓
React schedules a re-render
        ↓
Updated count appears in the UI

For example, when the count is 2 and the user clicks Increase, the updater function receives the previous value of 2 and returns 3. React then renders the component with the new count.


8. Understanding Increment, Decrement, and Reset

Increment

const increment = () => {
  setCount(previousCount => previousCount + 1);
};

This function increases the previous count by one. The updater form is useful when the new state depends on the previous state.

Decrement

const decrement = () => {
  setCount(previousCount => previousCount - 1);
};

This function decreases the previous count by one. It allows negative values unless a minimum limit is added.

Reset

const reset = () => {
  setCount(0);
};

This function resets the counter to its initial value of zero.

Prevent the Counter from Going Below Zero

If the application should never display a negative value, use a minimum limit:

const decrement = () => {
  setCount(previousCount =>
    Math.max(0, previousCount - 1)
  );
};

With this version, clicking Decrease while the count is 0 keeps the value at 0.


9. Using an Updater Function vs. Direct State Updates

React state behaves like a snapshot for the current render. Calling a state setter does not immediately change the variable inside the already-running handler. When the next value depends on the previous value, an updater function is a reliable choice.

Approach Example When to Use
Direct update setCount(count + 1) Suitable for a simple update based on the current render's value.
Updater function setCount(c => c + 1) Useful when the new value depends on the previous state or multiple updates are queued.
Reset to fixed value setCount(0) Useful when resetting to a known value.

Example: Increase the Count Three Times

const increaseThreeTimes = () => {
  setCount(c => c + 1);
  setCount(c => c + 1);
  setCount(c => c + 1);
};

Using updater functions allows React to process each queued update based on the result of the previous update. If the current count is 0, this handler increases it to 3.


10. Adding a Custom Increment Value

A more advanced counter can allow users to choose how much to add or subtract. This example uses a fixed increment of 5.

const incrementByFive = () => {
  setCount(c => c + 5);
};

const decrementByFive = () => {
  setCount(c => c - 5);
};

You can also store the custom amount in a separate state variable and allow the user to change it through an input field.


11. Creating a Reusable Counter Component

React components help you reuse counter logic in different parts of an application. Each independently rendered Counter component can maintain its own state.

import { useState } from 'react';

function Counter({ initialValue = 0, title = 'Counter' }) {
  const [count, setCount] = useState(initialValue);

  return (
    <section>
      <h2>{title}</h2>
      <p>Count: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>
        Increase
      </button>
      <button onClick={() => setCount(c => c - 1)}>
        Decrease
      </button>
      <button onClick={() => setCount(initialValue)}>
        Reset
      </button>
    </section>
  );
}

export default function App() {
  return (
    <div>
      <Counter title="Visitors" initialValue={0} />
      <Counter title="Points" initialValue={10} />
    </div>
  );
}

Note: initialValue is used to initialize the state. If the prop later changes, the existing state does not automatically reset. If that behavior is required, design an explicit reset or controlled-state pattern.


12. Counter Application with a Custom Increment Input

The following example extends the counter by allowing users to enter a custom step value. It includes input validation and a reset button.

import { useState } from 'react';

export default function App() {
  const [count, setCount] = useState(0);
  const [step, setStep] = useState('1');

  const parsedStep = Number(step);
  const validStep =
    step.trim() !== '' &&
    Number.isFinite(parsedStep) &&
    parsedStep > 0;

  return (
    <main className="counter-container">
      <h1>Smart Counter</h1>
      <p>Current count: {count}</p>
      <label htmlFor="step">Step value</label>
      <input
        id="step"
        type="number"
        min="1"
        value={step}
        onChange={event => setStep(event.target.value)}
      />
      <div className="button-group">
        <button
          disabled={!validStep}
          onClick={() => setCount(c => c + parsedStep)}
        >
          Increase
        </button>
        <button
          disabled={!validStep}
          onClick={() => setCount(c => c - parsedStep)}
        >
          Decrease
        </button>
        <button onClick={() => setCount(0)}>
          Reset
        </button>
      </div>
      {!validStep && (
        <p role="alert">Enter a number greater than zero.</p>
      )}
    </main>
  );
}

This example demonstrates multiple state variables, controlled inputs, input validation, conditional rendering, and functional state updates.


13. Important React Concepts Used in a Counter

Concept Purpose in the Counter Application
Functional Component Defines the interface and its behavior.
JSX Describes the elements displayed in the browser.
useState() Stores the current counter value.
Event Handler Responds to button clicks.
State Setter Requests an update to the state.
Re-rendering Allows the UI to display updated state.
Props Pass initial values or labels into reusable counters.
Conditional Rendering Shows messages according to the current count.
Controlled Input Keeps an input value synchronized with React state.
CSS Styles the counter layout and buttons.

14. Common Mistakes and Their Solutions

Mistake Why It Is a Problem Solution
Changing the state variable directly React may not re-render based on a direct mutation. Use the state setter function.
Calling a handler while rendering onClick={increment()} runs the function during rendering. Use onClick={increment}.
Forgetting to import useState The Hook will be undefined in the component. Import it from React.
Using the wrong initial value The counter begins at an unintended number. Set the required initial value, such as useState(0).
Allowing unwanted negative values The counter may go below zero. Use Math.max(0, count - 1) logic in the updater.
Expecting state to change immediately inside a handler The current render's state value remains a snapshot. Use updater functions when calculations depend on previous state.
Using invalid input values A custom step can be empty or invalid. Validate the input before updating the count.

15. Best Practices

  • Use descriptive names such as count, setCount, increment, and reset.
  • Use functional state updates when the next count depends on the previous count.
  • Keep components small and focused on one responsibility.
  • Use semantic HTML elements such as main, section, and button.
  • Provide visible focus indicators so the interface is usable with a keyboard.
  • Validate custom increment values before applying them.
  • Use aria-live where helpful to announce changes to assistive technology.
  • Keep state updates inside event handlers rather than changing state during ordinary rendering.
  • Test increment, decrement, reset, limits, and invalid input.
  • Separate styling into CSS files to make the component easier to maintain.

16. Testing Checklist

  • ☐ The initial count is 0.
  • ☐ Increase changes the count by one.
  • ☐ Decrease changes the count by one in the negative direction.
  • ☐ Reset returns the count to 0.
  • ☐ The status message reflects the count correctly.
  • ☐ The minimum limit works if enabled.
  • ☐ A custom step value works correctly.
  • ☐ Empty or invalid step values are handled safely.
  • ☐ Buttons are usable with a keyboard.
  • ☐ The layout remains readable on small screens.

17. Mini Project Enhancement Ideas

After building the basic Counter Application, try adding these features:

  1. Minimum and maximum limits: Prevent the counter from going below 0 or above 100.
  2. Custom step size: Allow the user to increase or decrease by a chosen amount.
  3. Dark mode: Add a button to switch between light and dark themes.
  4. Multiple counters: Display independent counters for different tasks.
  5. History: Show the previous counter values or actions.
  6. Undo: Restore the previous value after a counter update.
  7. Local storage: Save the counter value so it can be restored after a page refresh.
  8. Unit tests: Verify that increment, decrement, and reset work as expected.
  9. Responsive design: Improve the layout for mobile, tablet, and desktop screens.

18. Interview Questions and Answers

Q1. What is a Counter Application in React JS?

Answer: It is a simple interactive application that displays a numerical value and allows users to increase, decrease, or reset it using React components and event handlers.

Q2. Which Hook is commonly used to create a counter?

Answer: The useState() Hook is commonly used to store and update the counter value.

Q3. What does useState(0) mean?

Answer: It initializes a state variable with the value 0 and provides a setter function for updating that state.

Q4. What is the purpose of setCount()?

Answer: It requests a state update. React can then render the component again to display the updated count.

Q5. Why should state not be modified directly?

Answer: React relies on state setter functions to schedule updates correctly. Directly changing a variable does not reliably update the displayed UI.

Q6. What is an event handler?

Answer: An event handler is a function that responds to an event, such as clicking the Increase button.

Q7. What is the difference between state and props?

Answer: State is managed within a component using React features such as useState(). Props are values passed from a parent component to a child component.

Q8. Why use setCount(c => c + 1)?

Answer: It calculates the next value from the previous state, making it useful when multiple updates may be queued.

Q9. How can you prevent a counter from going below zero?

Answer: Use an updater such as setCount(c => Math.max(0, c - 1)).

Q10. What is re-rendering in React?

Answer: Re-rendering means React calls a component again to calculate its updated UI when relevant state or props change.

Q11. Can an application have multiple counters?

Answer: Yes. Each separately rendered Counter component can maintain independent state, or a parent component can manage shared state when the counters need to coordinate.

Q12. How can you test a Counter Application?

Answer: Verify the initial value, increment and decrement behavior, reset behavior, boundary conditions, invalid inputs, and keyboard accessibility.


19. Practice Exercises

  1. Create a counter that starts at 10.
  2. Add a button that increases the count by 5.
  3. Prevent the count from becoming negative.
  4. Display a message when the count reaches 50.
  5. Add a custom input for selecting the increment value.
  6. Create two independent Counter components on the same page.
  7. Add an Undo button that restores the previous count.
  8. Save and restore the counter value using local storage.
  9. Style the application with responsive CSS.
  10. Write tests for increment, decrement, and reset behavior.

20. Quick Revision

Topic Key Point
Counter Application Displays and updates a numerical value.
State Stores the current counter value.
useState() Provides the current state and its setter.
Increment Increases the count.
Decrement Decreases the count.
Reset Restores the counter to its initial value.
Event Handling Connects button clicks to functions.
Re-rendering Updates the UI after state changes.
Functional Updater Calculates the next state from the previous state.

21. Official Documentation and Learning Resources


22. Conclusion

A Counter Application is an excellent beginner project for learning React JS fundamentals. By creating increment, decrement, and reset buttons, learners practice functional components, JSX, the useState() Hook, event handling, and dynamic UI updates. Once the basic application works, adding custom step values, validation, multiple counters, accessibility features, and tests provides a pathway toward building more advanced React applications.

To learn more, visit the JustAcademy React JS Training Course or register for a React JS course demo.

whatsapp