Skip to main content

Command Palette

Search for a command to run...

Handling Events in React – Making UI Respond to Users

Updated
10 min readView as Markdown

A web application isn't useful if it only displays information.

Users need to:

  • Click buttons

  • Type into inputs

  • Submit forms

  • Hover over elements

  • Select options

  • Press keyboard keys

  • Interact with different parts of the UI

React provides a clean way to handle these interactions using Event Handlers.

On Day 63, I learned that State makes React components interactive.

Today, I'm learning how Events trigger those state changes.

The basic flow is:

User Interaction
       ↓
Event Handler
       ↓
State Update
       ↓
Component Re-renders
       ↓
Updated UI

🧠 What Are Events?

An event is something that happens because of an interaction or browser activity.

For example:

Click
Typing
Submit
Mouse Enter
Mouse Leave
Key Press
Change
Focus
Blur

In normal JavaScript, we might write:

button.addEventListener("click", handleClick);

In React, we generally write:

<button onClick={handleClick}>
  Click Me
</button>

React uses event props such as:

onClick
onChange
onSubmit
onMouseEnter
onMouseLeave
onFocus
onBlur
onKeyDown
onKeyUp

⚛️ React Event Naming

One important difference from HTML is camelCase.

HTML:

<button onclick="handleClick()">

React:

<button onClick={handleClick}>

Examples:

onClick
onChange
onSubmit
onMouseEnter
onMouseLeave

React event names are typically written in camelCase.


🖱️ onClick

The most commonly used React event is:

onClick

Example:

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

  return (
    <button onClick={handleClick}>
      Click Me
    </button>
  );
}

When the user clicks the button:

Click
 ↓
handleClick()
 ↓
"Button clicked!"

⚠️ Don't Call the Function During Rendering

This is a very important React concept.

❌ Incorrect

<button onClick={handleClick()}>
  Click
</button>

This executes the function while React is rendering.

✅ Correct

<button onClick={handleClick}>
  Click
</button>

Here, we're giving React the function to execute when the click occurs.


⚡ Inline Event Handlers

We can also write the function directly:

<button onClick={() => console.log("Clicked!")}>
  Click Me
</button>

This is useful for small actions.

For example:

<button onClick={() => alert("Hello!")}>
  Say Hello
</button>

🔥 Events + State

This is where today's lesson connects directly to Day 63.

import { useState } from "react";

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

  function increase() {
    setCount(prev => prev + 1);
  }

  return (
    <div>
      <h2>{count}</h2>

      <button onClick={increase}>
        Increase
      </button>
    </div>
  );
}

The complete flow is:

User clicks button
        ↓
onClick
        ↓
increase()
        ↓
setCount()
        ↓
State changes
        ↓
React re-renders
        ↓
New count displayed

This pattern appears everywhere in React.


📝 Handling Input Changes

One of the most important events for forms is:

onChange

Example:

function App() {
  function handleChange(event) {
    console.log(event.target.value);
  }

  return (
    <input
      type="text"
      onChange={handleChange}
    />
  );
}

Every time the user types, handleChange runs.


🎯 Understanding the Event Object

React passes an event object to the handler.

function handleChange(event) {
  console.log(event);
}

For an input:

event.target

represents the input element.

And:

event.target.value

gives us its current value.

For example, if the user types:

Saurabh

then:

event.target.value

will contain:

"Saurabh"

⚛️ Controlled Inputs

React applications commonly use controlled components.

Example:

import { useState } from "react";

function App() {
  const [name, setName] = useState("");

  function handleChange(event) {
    setName(event.target.value);
  }

  return (
    <div>
      <input
        value={name}
        onChange={handleChange}
      />

      <p>Hello, {name}</p>
    </div>
  );
}

Here the flow is:

User types
    ↓
onChange
    ↓
event.target.value
    ↓
setName()
    ↓
State updates
    ↓
Input + UI update

The state is controlling the input.

That's why it's called a controlled input.


🧠 Why Controlled Inputs Matter

Controlled inputs give React a reliable source of truth.

Instead of the input independently managing its value:

Input

we have:

React State
     ↓
   Input
     ↓
 User types
     ↓
onChange
     ↓
React State

This becomes extremely useful when building:

  • Login forms

  • Registration forms

  • Search bars

  • Filters

  • Checkout forms

  • Profile editors


📤 Handling Form Submission

React forms use:

onSubmit

Example:

function LoginForm() {
  function handleSubmit(event) {
    event.preventDefault();

    console.log("Form submitted");
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" />

      <button type="submit">
        Login
      </button>
    </form>
  );
}

🛑 What Does preventDefault() Do?

Normally, submitting an HTML form can trigger the browser's default form behavior.

In React applications, we often want to handle the submission ourselves.

So:

event.preventDefault();

prevents the browser's default behavior.

Then we can:

Read form data
      ↓
Validate data
      ↓
Send API request
      ↓
Display result

🧩 Complete Form Example

import { useState } from "react";

function LoginForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  function handleSubmit(event) {
    event.preventDefault();

    console.log({
      email,
      password
    });
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={event => setEmail(event.target.value)}
        placeholder="Email"
      />

      <input
        type="password"
        value={password}
        onChange={event => setPassword(event.target.value)}
        placeholder="Password"
      />

      <button type="submit">
        Login
      </button>
    </form>
  );
}

Now React controls both inputs and the form submission.


🖱️ Mouse Events

React supports several mouse events.

onMouseEnter

<div onMouseEnter={handleMouseEnter}>
  Hover over me
</div>

onMouseLeave

<div onMouseLeave={handleMouseLeave}>
  Leave me
</div>

onMouseDown

<button onMouseDown={handleMouseDown}>
  Press
</button>

onMouseUp

<button onMouseUp={handleMouseUp}>
  Release
</button>

These can be useful for interactive UI components.


⌨️ Keyboard Events

React also allows us to respond to keyboard interactions.

onKeyDown

<input
  onKeyDown={event => {
    console.log(event.key);
  }}
/>

If the user presses:

Enter

then:

event.key

will be:

"Enter"

🚀 Example: Detect Enter

function Search() {
  function handleKeyDown(event) {
    if (event.key === "Enter") {
      console.log("Search triggered");
    }
  }

  return (
    <input
      placeholder="Search..."
      onKeyDown={handleKeyDown}
    />
  );
}

This is commonly used for:

  • Search boxes

  • Chat applications

  • Command interfaces

  • Keyboard shortcuts


🎯 Passing Arguments to Event Handlers

Suppose we have:

function greet(name) {
  console.log(`Hello ${name}`);
}

We shouldn't write:

❌ onClick={greet("Saurabh")}

Instead:

<button onClick={() => greet("Saurabh")}>
  Greet
</button>

The arrow function delays execution until the click.


📦 Event Handler With Multiple Arguments

function handleUser(id, name) {
  console.log(id, name);
}

Then:

<button
  onClick={() => handleUser(101, "Saurabh")}
>
  Select User
</button>

This pattern is very useful when rendering lists.


🔄 Events and Props

Event handlers can also be passed through props.

Parent:

function App() {
  function handleClick() {
    console.log("Clicked!");
  }

  return <Button onClick={handleClick} />;
}

Child:

function Button({ onClick }) {
  return (
    <button onClick={onClick}>
      Click Me
    </button>
  );
}

The flow is:

Parent
  │
  │ passes function
  ↓
Child
  │
  │ user clicks
  ↓
Event Handler
  │
  ↓
Parent function runs

This is an important concept because it allows child components to communicate user interactions back to the parent.


🔥 Example: Child Button Updating Parent State

import { useState } from "react";

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

  function increaseCount() {
    setCount(prev => prev + 1);
  }

  return (
    <div>
      <h2>{count}</h2>

      <CounterButton onIncrease={increaseCount} />
    </div>
  );
}

function CounterButton({ onIncrease }) {
  return (
    <button onClick={onIncrease}>
      Increase
    </button>
  );
}

export default App;

Notice what's happening.

The child doesn't directly modify the parent's state.

Instead:

Child
 ↓
calls function received through props
 ↓
Parent updates state
 ↓
Parent re-renders

This follows React's one-way data flow.


🧠 Event Bubbling

Events can also propagate from a child element toward its ancestors.

Consider:

<div onClick={() => console.log("Parent")}>
  <button onClick={() => console.log("Button")}>
    Click
  </button>
</div>

Clicking the button can result in:

Button
  ↓
Parent

The event bubbles upward.

So you might see:

Button
Parent

in the console.

This concept becomes especially important when we later learn Event Delegation and more advanced interaction patterns.


🛑 Stopping Event Propagation

We can stop an event from continuing upward using:

event.stopPropagation();

Example:

function handleButtonClick(event) {
  event.stopPropagation();

  console.log("Button clicked");
}

Then:

<div onClick={() => console.log("Parent")}>
  <button onClick={handleButtonClick}>
    Click
  </button>
</div>

The button's event won't continue to the parent handler.


🧠 React Event Handling vs DOM Event Handling

You may notice that React feels similar to vanilla JavaScript.

Vanilla JS:

button.addEventListener("click", handleClick);

React:

<button onClick={handleClick}>

The major difference is that React lets us express the event handling directly as part of the component's UI declaration.


🏆 Best Practices

1. Use descriptive handler names

Prefer:

handleSubmit
handleLogin
handleSearch
handleDelete
handleToggle

instead of:

fn1
abc
click

2. Keep event handlers focused

Instead of putting huge amounts of logic inside JSX:

<button
  onClick={() => {
    // 30 lines of logic
  }}
>

prefer:

function handleClick() {
  // logic
}

Then:

<button onClick={handleClick}>

3. Use functional updates when updating from previous state

setCount(prev => prev + 1);

4. Use preventDefault() when you need custom form behavior

function handleSubmit(event) {
  event.preventDefault();
}

5. Pass functions, don't execute them

onClick={handleClick}

onClick={handleClick()}

6. Use state for UI-driven changes

Events become especially powerful when connected to state.

Event
 ↓
Handler
 ↓
State
 ↓
UI

🧪 A Complete Interactive Example

Let's combine today's concepts.

import { useState } from "react";

function App() {
  const [name, setName] = useState("");
  const [submittedName, setSubmittedName] = useState("");

  function handleSubmit(event) {
    event.preventDefault();

    setSubmittedName(name);
  }

  return (
    <div>
      <h1>Welcome</h1>

      <form onSubmit={handleSubmit}>
        <input
          value={name}
          onChange={event => setName(event.target.value)}
          placeholder="Enter your name"
        />

        <button type="submit">
          Submit
        </button>
      </form>

      {submittedName && (
        <p>
          Hello, {submittedName}! 👋
        </p>
      )}
    </div>
  );
}

export default App;

This tiny application uses:

  • State

  • useState

  • onChange

  • onSubmit

  • Event object

  • preventDefault()

  • Controlled input

  • Conditional rendering

And that's already starting to look like a real application.


💡 My Biggest Takeaway

Today's biggest takeaway is:

Events are the bridge between the user and React State.

State stores the data.

Events detect what the user does.

Event handlers decide what should happen.

React then updates the UI.

The complete mental model is:

User
 ↓
Interaction
 ↓
React Event
 ↓
Event Handler
 ↓
State Update
 ↓
Re-render
 ↓
Updated UI

Once this pattern becomes natural, building interactive React applications becomes much easier.


🚀 Final Summary

Today I learned:

  • What events are

  • React event handlers

  • onClick

  • onChange

  • onSubmit

  • Mouse events

  • Keyboard events

  • Event objects

  • event.target

  • event.target.value

  • Controlled inputs

  • preventDefault()

  • Passing arguments to handlers

  • Passing event handlers through props

  • Parent-child event communication

  • Event bubbling

  • stopPropagation()

  • Event handling best practices

Yesterday:

State → stores changing data

Today:

Events → respond to user interactions

Together:

User Interaction
       ↓
      Event
       ↓
 Event Handler
       ↓
      State
       ↓
    Re-render
       ↓
   Updated UI

That's the foundation of interactive React applications. ⚛️🚀

100 Days of Code: My Journey to Becoming a Full Stack Developer

Part 1 of 50

Welcome to my 100 Days of Code journey! In this series, I'll document my daily progress as I learn Full Stack Web Development from the ground up. Every post will cover what I learned, challenges I faced, mistakes I made, and the projects I built. My goal is not just to complete 100 days but to become a better developer through consistency, discipline, and learning in public. Topics I'll cover include: • Git & GitHub • HTML, CSS & JavaScript • React.js • Node.js & Express • MongoDB • APIs • Real-world Projects • AI tools for Developers Whether you're just starting out or revising your fundamentals, I hope this journey helps you learn alongside me. Let's build, learn, and grow together! 🚀

More from this blog

T

TheSaurceCode

73 posts

Documenting my journey to becoming a Full Stack Developer through daily blogs, coding challenges, projects, tutorials, and lessons learned. Learn, build, and grow with me