How to Handle Events in React JS

A React dashboard can look perfect until users start clicking buttons, typing into fields, and changing filters. That is when event handling turns a static screen into a working application.

I have used this pattern in task dashboards where users add tasks, mark them complete, and switch between newest-first and oldest-first views. The key is connecting browser actions to clean state updates without mutating your data.

You will learn how to handle events in React JS using functional components, useState, event objects, and a practical task dashboard example.

How to Handle Events in React JS

React events let your component respond to user actions such as clicks, text input, form submissions, keyboard presses, and mouse movement. You attach an event handler—a function that runs after an action—to a JSX element.

In React, event names use camelCase. For example, use onClick instead of HTML’s lowercase onclick.

Here is the smallest useful example:

function SaveButton() {
function handleSave() {
alert("Task saved");
}

return <button onClick={handleSave}>Save Task</button>;
}

The handleSave function does not run while React renders the component. React stores it and calls it only when the user clicks the button.

Notice that we pass the function name without parentheses:

<button onClick={handleSave}>Save Task</button>

This is correct because React needs a function to call later. The following code runs immediately during rendering, which causes problems:

<button onClick={handleSave()}>Save Task</button>

Use a named handler when the logic has more than one line. It makes the JSX easier to scan and helps you reuse the same action in another component. If you are new to component inputs, see this guide on working with props in React JS.

Build a Task Dashboard

Let’s use one real-world example throughout this guide: a task dashboard that can add tasks, complete them, and display the newest task first.

This example assumes a modern React app using functional components and the useState Hook. A Hook is a React function that lets a functional component remember data between renders.

import { useState } from "react";

const initialTasks = [
{ id: 1, title: "Review client feedback", completed: false },
{ id: 2, title: "Update dashboard filters", completed: false },
{ id: 3, title: "Publish weekly report", completed: true }
];

export default function TaskDashboard() {
const [tasks, setTasks] = useState(initialTasks);
const [taskTitle, setTaskTitle] = useState("");

return (
<main>
<h1>My Tasks</h1>
</main>
);
}

The tasks variable holds the current task list. The setTasks function updates that list. Together, they form your component state, which is data React tracks for the current component.

The taskTitle state stores what the user types into the input field. Keeping form values in state gives React control over the visible value, which is useful for validation, clearing fields, and submitting data.

For a broader view of keeping UI data organized, read about React component state management.

Handle Click Events

A click handler is one of the most common ways to handle events in React JS. You will use it for buttons in dashboards, admin panels, dialogs, menus, and task lists.

Add a button that logs a simple message:

function TaskDashboard() {
function handleRefresh() {
console.log("Refreshing task data");
}

return (
<main>
<button onClick={handleRefresh}>Refresh Tasks</button>
</main>
);
}

When the user clicks the button, React calls handleRefresh. The button does not need special JavaScript selectors or manual DOM code. React handles the connection through the onClick prop.

You can also use an inline arrow function when you need to pass a value:

<button onClick={() => console.log("Task ID: 3")}>
View Task
</button>

The arrow function delays the console.log() call until the click happens. This approach works well for small list actions, such as deleting a task by ID.

<button onClick={() => handleDeleteTask(task.id)}>
Delete
</button>

Avoid putting long logic inside JSX. A named function keeps your render code focused on the interface rather than business rules.

Handle Events in React JS With State

Most useful event handlers update the UI. In React, you update the UI by calling a state setter instead of changing a variable directly.

Add a task-completion button to the dashboard:

function handleCompleteTask(taskId) {
setTasks((currentTasks) =>
currentTasks.map((task) =>
task.id === taskId
? { ...task, completed: true }
: task
)
);
}

The map() method creates a new array. For the selected task, the spread operator creates a new object with completed changed to true. Every other task stays unchanged.

This approach follows immutability, which means you create new values instead of changing existing state values directly. React can then detect that state changed and render the updated interface.

Render the task list like this:

<ul>
{tasks.map((task) => (
<li key={task.id}>
<span>
{task.title} {task.completed ? "✅" : "⏳"}
</span>

{!task.completed && (
<button onClick={() => handleCompleteTask(task.id)}>
Mark Complete
</button>
)}
</li>
))}
</ul>

The key prop gives each rendered list item a stable identity. Use a unique database ID whenever possible. Do not use the array index when users can add, remove, filter, sort, or reverse items.

You can learn more about choosing list keys in this guide on the React component key prop.

Handle Input Change Events

Text inputs need an onChange event handler. React passes an event object to the handler, and the current input value lives in event.target.value.

Add an input to your task dashboard:

<input
type="text"
value={taskTitle}
onChange={(event) => setTaskTitle(event.target.value)}
placeholder="Enter a task"
/>

This is a controlled component. React state controls the input value, and every keystroke updates that state.

For more readable code, move the event logic into a separate function:

function handleTitleChange(event) {
setTaskTitle(event.target.value);
}

Then use it in JSX:

<input
type="text"
value={taskTitle}
onChange={handleTitleChange}
placeholder="Enter a task"
/>

This pattern becomes more helpful when you need to trim text, validate characters, update several fields, or trigger suggestions from an API.

Handle Form Submit Events

Use a form when users enter and submit data. Forms support keyboard behavior automatically, including submitting when the user presses Enter inside an input.

Add this form to the dashboard:

<form onSubmit={handleAddTask}>
<input
type="text"
value={taskTitle}
onChange={handleTitleChange}
placeholder="Enter a task"
/>

<button type="submit">Add Task</button>
</form>

Now create the submit handler:

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

const cleanTitle = taskTitle.trim();

if (!cleanTitle) {
return;
}

const newTask = {
id: Date.now(),
title: cleanTitle,
completed: false
};

setTasks((currentTasks) => [...currentTasks, newTask]);
setTaskTitle("");
}

The event.preventDefault() line stops the browser from reloading the page after form submission. That reload is normal browser behavior, but it would reset your React application.

The handler then trims extra spaces, stops empty tasks, creates a task object, and appends it to the existing list. The useState updater function receives the latest task array, which makes it safer when React batches updates.

Finally, setTaskTitle("") clears the controlled input. If you need more form patterns, this article on form validation in React JS is a useful next step.

Reverse a React Task Array Safely

Task dashboards often show the newest task at the top. Since the previous example adds new tasks to the end of the array, you may want to reverse the display order before rendering.

This is where many React bugs start. JavaScript’s reverse() method changes the original array. That is safe only when you intentionally want to mutate a normal local array. It is not safe to call directly on a React state array.

Do not do this:

const newestFirst = tasks.reverse();

This code changes tasks itself. Since tasks comes from state, you have mutated React state without calling setTasks. That can create confusing list behavior, stale UI, and bugs that appear after another event runs.

Use a copied array instead:

const newestFirst = [...tasks].reverse();

The spread operator creates a shallow copy of the task array. Then reverse() changes only that copied array, leaving the original React state untouched.

Render the copied array:

const newestFirst = [...tasks].reverse();

return (
<ul>
{newestFirst.map((task) => (
<li key={task.id}>
{task.title}
</li>
))}
</ul>
);

This approach works well when state stores the source of truth in one order, while the UI needs another order. For example, an API may return oldest-first activity data, while users expect a newest-first feed.

Modern JavaScript also provides toReversed():

const newestFirst = tasks.toReversed();

Unlike reverse(), toReversed() returns a new array and keeps the original untouched. It reads well and directly communicates your intent. Use it when your supported browsers and build tools handle newer JavaScript features.

Pro Tip: I’ve found that keeping the original API order in state and creating a reversed display value prevents bugs when users switch sorting, filter tasks, or open task details from a list.

Add a Reverse Order Button

Sometimes users need to choose their own display order. You can handle that click event with a Boolean state value.

const [showNewestFirst, setShowNewestFirst] = useState(true);

function handleToggleOrder() {
setShowNewestFirst((currentValue) => !currentValue);
}

Now derive the visible tasks from the user’s preference:

const displayedTasks = showNewestFirst
? [...tasks].reverse()
: tasks;

Add the button and render the list:

<button onClick={handleToggleOrder}>
Show {showNewestFirst ? "Oldest" : "Newest"} First
</button>

<ul>
{displayedTasks.map((task) => (
<li key={task.id}>
{task.title}
</li>
))}
</ul>

You can see the output in the screenshot below.

Handle Events in React JS

This is better than storing a second reversed task array in state. The order is a derived value, meaning React can calculate it from the original tasks state and showNewestFirst setting.

A derived value prevents duplicated data. If you store both arrays, you must keep both updated after every add, delete, and completion event.

Things to Keep in Mind

  • Do not mutate state: Calling tasks.reverse() changes the existing React state array and can cause inconsistent rendering.
  • Copy before reversing: Use [...tasks].reverse() when you need a reverse array without mutation in older JavaScript environments.
  • Use stable key props: Keep the same unique task ID as the key prop after reversing so React tracks each list item correctly.
  • Avoid duplicate state: Store the original task array and derive the reversed list during rendering instead of maintaining two arrays.
  • Watch repeated work: Reversing a small dashboard list during render is usually fine, but consider memoizing expensive transformations for very large data tables.
  • Check toReversed() support: toReversed() creates a new array, but older browser targets may need transpilation or a fallback.

Frequently Asked Questions

How do I handle events in React JS?

Attach a handler function to a JSX event prop such as onClickonChange, or onSubmit. React calls that function after the related user action occurs. Use state setters such as setTasks to update the interface.

How do I reverse an array in React?

Create a copy first, then call reverse():
const reversedTasks = [...tasks].reverse();
This keeps the original React state array unchanged while giving you a reversed array for rendering.

Why does reverse() cause problems in React state?

The reverse() method changes the original array in place. If that array comes from useState, you mutate state directly instead of creating a new value. React code becomes harder to predict when state changes outside its setter function.

Can I use reverse() inside JSX?

You can, but avoid calling it directly on state. Use a copied array in JSX, such as {[…tasks].reverse().map(…)}, for small lists. For readability, I prefer assigning the derived list to a variable before the return statement.

Should I store the reversed array in state?

Usually, no. Keep one source-of-truth array in state and derive the reversed order when rendering. Store a separate showNewestFirst Boolean only when the user can change the display order.

What is the difference between reverse() and toReversed()?

reverse() mutates the array it runs on. toReversed() returns a new reversed array and does not alter the original. In React applications, toReversed() is safer when your browser support requirements allow it.

React event handling becomes much easier when you keep event functions focused and update state immutably. For task lists, copy the array before using reverse(), or use toReversed() when it fits your supported environment. I hope you found this article helpful.

You May Also Like

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.