DEV Community

shash68i
shash68i

Posted on

Handling Events in React

This is going be a concise article on handling events in React. While teaching React to several students, I observed that many beginners often get confused in how to handle events in React, so I decided to write an article about this.

Let's Begin!

There are 4 scenarios which arises when handling events -

  1. Event Handler without any data or event object
  2. Event Handler with event object only
  3. Event Handler with data only
  4. Event Handler with event object and data both

You just need to remember these 4 scenarios, let's go one by one through each case.

CASE 1: Event Handler without any data or event object

export default function App() {

  // Observe the below function definition carefully
  const handleClick = () => {
    console.log("Clicked");
  };

  return (
    <div className="App">
      // Observe below line carefully
      <button onClick={handleClick}>Click Me</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the above code block, we have just passed the reference of the function handleClick to the onClick prop.
**Remember, we're not calling the function with parenthesis like this onClick={handleClick()}, we're just passing the reference of the function like this onClick={handleClick}. If we call the function like this onClick={handleClick()} then function will be executed right during the rendering, which we don't want. **Passing the function is possible because functions are first class citizens in Javscript, if you want to know more, I have written an article about this, read here.

This is the simplest way of handling any event where you don't need to pass anything in the function or doesn't require event object.

CASE 2: Event Handler with event object only

export default function App() {

  // Observe the function below & its parameters carefully
  const handleClick = (event) => {
    console.log("Event Object", event);
  };

  return (
    <div className="App">
      // Observe below line & relate with handleClick's definition
      <button onClick={handleClick}>Click Me</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Just like the CASE 1, we're passing the function reference to the onClick event in the same way. The difference here is the function definition. The definition of the function handleClick is having a parameter event (you can name this anything).

Remember that we're just passing the function's reference and React is calling the function later on our behalf when the event fires. When react executes the function on the event fire, it automatically passes the event object as an argument, so you can access it inside the function. This event object consists of many important details related to the event which is fired, such as event.target, event.clientX, event.clientY, etc.

CASE 3: Event Handler with data only

export default function App() {

  // Observe the function below & its parameters carefully
  const handleClick = (data) => {
    console.log(data);
  };

  return (
    <div className="App">
      // Observe below 3 lines & relate with handleClick's definition
      <button onClick={() => handleClick(1)}>Button 1</button>
      <button onClick={() => handleClick(2)}>Button 2</button>
      <button onClick={() => handleClick(3)}>Button 3</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

There are many cases where you want to pass something of your own, apart with the default event object. For example- Let's say you have a list of items and you have buttons to delete the items on clicking them, how would the event handler know which item's button is clicked. In these kind of scenarios we need to inform the event handler about which one is clicked, so we pass the id or some information related to that button.

In the above code we're passing the number of the button in
handleClick. You might think that we're executing the function by doing this onClick={() => handleClick(1), but observe carefully we're calling the handleClick with some data(here 1) but we're not passing the executed function in onCLick, we're passing an another anonymous function definition in onCLick which function is inside calling the handleClick(1).
So, we didn't change our way. We're still only passing a function reference or function definition to onClick.

You can pass anything which is in or outside the scope of wrapping function as arguments as long as you're accepting those arguments in handleClick's parameters. The condition is to just wrap the handler function in a function and pass that function to onClick listener.

See few examples below -

import { useState } from "react";

export default function App() {
  const [text, setText] = useState("Hello World");

  // Observe the function below & its parameters carefully
  const handleClick = (data, text) => {
    console.log(data, text);
  };

  return (
    <div className="App">
      // Observe below line & relate with handleClick's definition
      <button onClick={() => handleClick(1, text)}>Button</button>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

In the above code, handleClick has 2 parameters data and text and we're passing 1 and text from state variable while calling the function, wrapped the handleClick(1, text) inside an anonymous function and passed that to onClick.
Our 4th case is just a slight modification of this, let's talk about that.

CASE 4: Event Handler with event object and data both

We have seen how to pass data without event object and how to get event object without data, but things are little different when we want to access both inside our event handler function.

import { useState } from "react";

export default function App() {
  const [text, setText] = useState("Hello World");

  // Observe the function below & its parameters carefully
  const handleClick = (event, data, text) => {
    console.log(data, text, event.type);
  };

  return (
    <div className="App">
      // Observe the line below & relate with handleClick's definition
      <button onClick={(e) => handleClick(e, 1, text)}>Button</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

When you need to get some data as well as the event object inside the handler function then you need to pass all of them as arguments while calling the function and have all of them as parameters while defining the function. Also you need to pass the event object in the wrapper function.

Let's understand with our code example. In the above code, while defining handleClick const handleClick = (event, data, text) => { ... }, we have all the data we want to access as parameters (data and text in our case), we also have the event object as a parameter (you can name it anything, we have named it event, hence it'll be accessible by name event inside handleClick.

Now, while calling the function, we need to pass arguments in the same order onClick={(e) => handleClick(e, 1, text)}. Remember, in CASE 2 if we wanted to access the event object then we didn't need to pass event object while passing handleClick to onClick. But if you want to get some data as well as event object then you have to go by this way.

Look at this onClick={(e) => handleClick(e, 1, text)}, we're doing almost the same thing as we did for CASE 3 with a small difference. We're passing event object as an argument (we have named it e here) with 1 and text from state variable, you can see that we can pass 1 directly and we can pass text also, because it is outside the scope of the wrapper function so we can access it. But where can we find the event object related to that particular listener? That we'll get from the argument of the wrapper function we passing to the onClick. That's the catch here.

So these are the only 4 ways to play around events.

Here's a summary of all of that -

CASE 1:

const handleClick = () => { ... };

<button onClick={handleClick}>Click Me</button>
Enter fullscreen mode Exit fullscreen mode

CASE 2:

const handleClick = (event) => { //Access event inside };

<button onClick={handleClick}>Click Me</button>
Enter fullscreen mode Exit fullscreen mode

CASE 3:

const handleClick = (data1, data2) => { //Access data inside };

<button onClick={() => handleClick(d1, d2)}>Click Me</button>
Enter fullscreen mode Exit fullscreen mode

CASE 4:

const handleClick = (event, data1, data2) => { //Access them inside };

<button onClick={(e) => handleClick(e, d1, d2)}>Click Me</button>
Enter fullscreen mode Exit fullscreen mode

And this wraps up the event handling scenarios in React. If you're a beginner and facing difficulty in understanding the patterns here, please read it twice to connect the dots.

Feel free to connect with me on Twitter for feedback, ideas, suggestions, etc.

Thank You so much for your valuable time and reading it till the end 😊!

Top comments (0)