Handling Events in React
Tags: webdev, javascript, tutorial, react
Published: 2023-04-13 16:07:19

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**

``` javascript
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>
  );
}
```
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](https://shash68i.hashnode.dev/debouncing-in-javascript-for-everyone#heading-functions-are-first-class-objects). 

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**


``` javascript
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>
  );
}
```
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**


```javascript
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>
  );
}
```
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 - 

```javascript
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>
  );
}

```
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.

```javascript
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>
  );
}
```

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:**
```javascript
const handleClick = () => { ... };

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

**CASE 2:**
```javascript
const handleClick = (event) => { //Access event inside };

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

**CASE 3:**
```javascript
const handleClick = (data1, data2) => { //Access data inside };

<button onClick={() => handleClick(d1, d2)}>Click Me</button>
```
**CASE 4:**
```javascript
const handleClick = (event, data1, data2) => { //Access them inside };

<button onClick={(e) => handleClick(e, d1, d2)}>Click Me</button>
```


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](https://twitter.com/shash68i) for feedback, ideas, suggestions, etc.

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