DAY 7 : Mastering useState in React with a Beginner-Friendly Counter App | My Web Dev Journey (ReactJS)

Ritik KumarRitik Kumar
9 min read

Introduction

Welcome to Day 7 of my web development journey!
For the past few days, I’ve been diving into ReactJS after completing the fundamentals of HTML, CSS, and JavaScript.

I learnt concepts like state management, event handling,conditional rendering and build a project to grasp these concepts.

I'm sharing my learning process in public to stay consistent and hopefully help others who are on a similar path.

Here’s what I learnt in last 3 days:

  • Day 4:
    → Event Handling
    → State
    → useState() hook

  • Day 5:
    → React Fragment
    → Condional Rendering

  • Day 6:
    → Did Project to understand these concepts
    → Counter App

Let’s break down each of these topics below 👇


1. Event Handling:

Event Handling is the way we respond to user interactions, such as clicking button, typing in input field, etc..

React has its own Synthetic event system that wraps around the browser's native events to provide better performance and cross-browser compatibility.

In HTML/JS, We add event something like this:

<button onclick="doSomething()">Click Me</button>

But in React, the syntax is a bit different. Events are written in camelCase(onClick not onclick), and instead of a string, we pass a function reference.

How Event Handling Works in React?

Here’s a simple example I built while learning:

function App() {
  const handleClick = () => {
    console.log("Button clicked!");
  };

  return (
    <div>
      <h1>Hello React</h1>
      <button onClick={handleClick}>Click Me</button>
    </div>
  );
}

export default App;

onClick is the event.
handleClick is the function that gets called when the button is clicked.

Things I Learned:

1. CamelCase Events

React uses camelCase for event names. So it’s onClick, onChange, onSubmit, etc., not lowercase like in HTML.

2. Pass Function, Don’t Call It

I mistakenly wrote onClick={handleClick()} and it ran automatically when the page loaded!
So I learned: always pass the function reference, not a function call.

3. Arrow Functions for Parameters

If I want to pass custom arguments to the function, I need to wrap it in an arrow function:

<button onClick={() => handleClick("React is awesome!")}>Click</button>

4. Synthetic Events

React wraps native events inside something called a SyntheticEvent. This ensures events work the same across all browsers. I didn’t dive too deep into it, but it’s good to know!


2. Understanding State:

In React, state refers to a way of tracking and managing data that can change over time in a component.

For example, if I want to show a counter that updates whenever I click a button, I need to store and update that number — and that’s where state comes in.

I learned that state helps React re-render the UI whenever something changes.

But wait, how do we create state in React?

That’s where the useState() hook comes in!

3. useState() – My First React Hook:

useState() is a Hook that lets us add state to functional components.

It is local to the component.

Triggers re-render if state is updated.

Syntax:

const [stateVariable, setStateFunction] = useState(initialValue);
  • stateVariable is the current value of the state.
  • setStateFunction is the function used to update the state.
  • initialValue is the initial value of the state(can be a number, string, object, arrays,etc..)

Example - Simple Counter:

import { useState } from "react";

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

  function increase() {
    setCount(count + 1);
  }

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={increase}>Increase</button>
    </div>
  );
}

Every time I click the button, the increase function is triggered, which updates the state using setCount.
React then re-renders the component with the new count value.
React ensures that new value is shown on the screen.

Things I Learned:

  • State allows components to react to user input or internal events.
  • useState() can only be used inside functional components — I tried it outside once and got an error!
  • State updates are asynchronous — so I learned not to expect count to update immediately in the next line.
  • I must never mutate the state directly, like doing count++.
  • Instead, always use the state updater function like: setCount(count + 1).

4. React Fragment:

A React Fragment lets us group multiple elements without adding extra node to the DOM.

Normally, JSX allows us to return only one parent element. So we often use a <div> to wrap things — but too many <div> can clutter the HTML and break the structure in some layouts. That’s where React Fragment comes in.

When we want to return multiple sibling elements from a Component without wrapping them in extra <div>, We use a react fragment.

How to use React Fragment:

1. Full Syntax:

const App = () => {

  return (
    <React.Fragment>
      <h1>Hello</h1>
      <p>This is inside a fragment</p>
    </React.Fragment>
  )

}

2. Short Syntax:

const App = () => {

  return (
    <>
      <h1>Hello</h1>
      <p>This is using short syntax</p>
    </>
  )

}

Things I Learned:

  • React Fragment lets us return multiple elements without extra HTML nodes.
  • Short syntax <> </> is super convenient but can’t accept props like key.
  • Use full syntax (<React.Fragment>) when we need to pass attributes.

5. Condional Rendering:

Conditional rendering in React means showing different UI elements based on certain conditions — like if-else in JavaScript, but inside JSX!

For example, we can decide whether to show a message, a button, or even an entire component depending on user actions or app state.

Common Methods:

1. Using if Statements (Outside JSX)

This felt familiar from JavaScript. I used an if block before the return statement.
Best for complex logic where multiple branches are needed.

if (isLoggedIn) {
  return <h1>Welcome back!</h1>;
}
return <h1>Please sign in.</h1>;

It’s clean but only works outside JSX, not directly inside the return().

2. Ternary Operator (Inline If-Else)

This is my favorite so far. I used it directly in JSX.

<h1>{isLoggedIn ? "Welcome back!" : "Please sign in."}</h1>
  • It's compact and neat.
  • Easy to understand if the condition is simple.
  • Great for rendering small changes in the UI.

3. Logical AND Operator (&&)

When I just wanted to show something only if a condition is true, I used &&.

{isLoggedIn && <button>Logout</button>}
  • If isLoggedIn is true, it renders the button.
  • If false, it renders nothing.

Super helpful for toggling UI elements.

One Mistake I Made:

I tried to put an if condition directly inside JSX and React threw an error.

{/* This doesn’t work! */}
<h1>{if (isLoggedIn) { "Welcome!" }}</h1>

So, I learned that only expressions (not full statements) work inside JSX.


6. Counter App Project:

After learning React basics like useState, event handling, and conditional rendering, I built a simple Counter App to apply these concepts in a real project.

This app allows the user to:

  • Increment the counter value
  • Decrement the counter value
  • Reset the counter to zero

The main goal was to practice managing state, handling user events, and rendering elements conditionally based on the state.

Project Features:

  • Increment the counter by 1.
  • Decrement the counter by 1.
  • Reset the counter to 0.
  • Show error message when counter is at 0 (to avoid negative numbers).
  • Can change step value (by default it is 1).

Concepts I Applied:

1. useState Hook

I used useState() to keep track of the:

  • count
  • input value
  • error message
    const [count, setCount] = useState(0);
    const [value, setValue] = useState(1);
    const [error, setError] = useState("");
    

2. Event Handling

I added onClick handlers to Button Component to update the count:

<Button onClick={minusBtn} btnClass="minus" content="-" />
<Button onClick={plusBtn} btnClass="plus" content="+" />
<Button onClick={resetBtn} btnClass="reset-btn" content="Reset" />

Each button runs a function that updates the state based on the user’s action.

3. Conditional Rendering

I show the error message when count become negative using conditional rendering.

{error && <p className="err-message">{error}</p>}

This made the UI feel interactive and dynamic!

Code:

1. App.jsx

import MainContainer from "./Components/MainContainer";

const App = () => {
  return (
    <div className="wrapper">
      <MainContainer />
    </div>
  );
};

export default App;

2. MainContainer.jsx

import ContentContainer from "./ContentContainer";

function MainContainer() {
  return (
    <main>
      <h1>Counter App</h1>
      <ContentContainer />
    </main>
  );
}

export default MainContainer;

3. ContentContainer.jsx

import { useState } from "react";
import Button from "./Button";
import IncrementDecrement from "./IncrementDecrement";
import PlusMinusBtnContainer from "./PlusMinusBtnContainer";

const ContentContainer = () => {
  const [count, setCount] = useState(0);
  const [value, setValue] = useState(1);
  const [error, setError] = useState("");

  function resetBtn() {
    setCount(0);
    setValue(1);
    setError("");
  }

  return (
    <div className="container">
      <p className="result">{count}</p>

      <PlusMinusBtnContainer
        count={count}
        setCount={setCount}
        value={value}
        setError={setError}
      />

      {error && <p className="err-message">{error}</p>}

      <IncrementDecrement value={value} setValue={setValue} />

      <Button onClick={resetBtn} btnClass="reset-btn" content="Reset" />
    </div>
  );
};

export default ContentContainer;

4. PlusMinusBtnContainer.jsx

import Button from "./Button";

const PlusMinusBtnContainer = ({ count, setCount, value, setError }) => {
  function minusBtn() {
    if (count - value >= 0) {
      setCount(count - value);
      setError("");
    } else {
      setError("Cannot go below zero");
    }
  }

  function plusBtn() {
    setCount(count + value);
    setError("");
  }

  return (
    <div className="plus-minus-btn-container">
      <Button onClick={minusBtn} btnClass="minus" content="-" />
      <Button onClick={plusBtn} btnClass="plus" content="+" />
    </div>
  );
};

export default PlusMinusBtnContainer;

5. IncrementDecrement.jsx

const IncrementDecrement = ({ value, setValue }) => {
  function handleInput(e) {
    const inputvalue = e.target.value;

    if (inputvalue === "") {
      setValue("");
    } else {
      setValue(Number(inputvalue));
    }
  }

  return (
    <p className="increment-decrement">
      Increment/Decrement by:
      <input
        value={value}
        onChange={handleInput}
        className="number-input"
        type="number"></input>
    </p>
  );
};

export default IncrementDecrement;

6. Button.jsx

const Button = ({ btnClass = "", content = "click", onClick }) => {
  return (
    <button onClick={onClick} className={`btn ${btnClass}`}>
      {content}
    </button>
  );
};

export default Button;

Things I Learned:

  • How useState keeps track of changes and re-renders the UI.
  • The importance of passing function references, not calling them directly.
  • How to conditionally show elements using && or ternary operators.
  • That even a basic project can reinforce multiple core concepts!

7. What's next:

I’m continuing this journey and will be:


8. Conclusion:

This part of my React journey helped me understand some of the most important building blocks of any React app:

  • How events are handled differently in React using camelCase syntax.
  • The concept of state and how useState() allows us to make our components dynamic and interactive.
  • The role of React Fragments in keeping our DOM clean without unnecessary wrapper elements.
  • How to show or hide elements using conditional rendering techniques like && and ternary operators.
  • And finally, how a simple project like a Counter App can bring all these concepts together in a practical and fun way!

Every small project or topic I explore builds a stronger foundation, and I’m excited to keep learning and building more with React!

If you're on a similar journey, feel free to reach out or follow along — we’re all in this together.

1
Subscribe to my newsletter

Read articles from Ritik Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ritik Kumar
Ritik Kumar

👨‍💻 Aspiring Software Developer | MERN Stack Developer.🚀 Documenting my journey in Full-Stack Development & DSA with Java.📘 Focused on writing clean code, building real-world projects, and continuous learning.