Advantages and Understanding of using Currying Function pattern in onClick Event handler in React

Viewed 1581

I need some help in understanding the following working code for onClick EventHandler. A detailed explanation will be really appreciated in understanding why a function is returning another function here.

const MyComponent = (props) => {
  const onClickHandler = (somearg) => (e) => {
       console.log(`somearg passed successfully is ${somearg}`)
  };

  return (
    <div onClick={onClickHandler(somearg)}>
    </div>
  );
};



export default MyComponent;
2 Answers

The pattern you're referring to is called "currying". I'll explain why that pattern can be useful later in the answer, but first let's try to understand exactly what's happening.

As you've already identified, the onClickHandler function returns a new function, it doesn't actually add much outside of that. Now what this means is that when the component renders, onClickHandler will be called immediately. So writing this:

<div onClick={onClickHandler('test')}>

Will end up returning this:

<div onClick={(e) => {console.log(`somearg passed successfully is ${somearg}`)}}>

This is why here you're allowed to call the function in the JSX, even though (like you pointed out) you can't do that most other times. The reason is because it's the returned function that will actually handle the click.

Now lets talk more about why this pattern is useful. somearg is vague, but we'll stick with it for now until we get to the other benefits.

"currying" uses a closure to sort of "freeze" the value of somearg for use by the returned function. Looking at the above example of the returned function, somearg would appear to not exist. However, with a closure, somearg will not only be available, but will also retain the value of 'test'.

So why use this pattern?

This pattern allows you to reuse functions in ways otherwise not possible. Consider a usecase where we have 2 div's that should be clickable. They should both do the same thing, but it may be helpful to be able to distinguish which div was clicked in order to complete that operation.

For simplicity, lets just say we have two div's, and when clicked we want each to log their order.

Here's how you might do that without currying:

const Example = () => {
  const onClickHandler1 = (e) => {
    console.log("I am the 1 div.");
  };
  
  const onClickHandler2 = (e) => {
    console.log("I am the 2 div.");
  };
  
   return (
     <div>
      <div onClick={onClickHandler1}>1</div>
      <div onClick={onClickHandler2}>2</div>
     </div>
   );
}

ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

The above works just fine, but our two functions have a lot of shared functionality. It seems unnecessary to have both. So one solution would be to use currying:

const Example = () => {
  // Converted to longer form so its possible to console.log in the first function
  // It still operates identically to the short-hand form.
  const onClickHandler = (order) => {
    console.log("called with " + order);
    return (e) => console.log("I am the " + order + " div.");
  };
  
   return (
     <div>
      <div onClick={onClickHandler(1)}>1</div>
      <div onClick={onClickHandler(2)}>2</div>
     </div>
   );
}

ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

As you can see in the above example, onClickHandler gets called twice as soon as the component renders. But the first time, order is "frozen" or "closed over" with the value of 1, and the second has the value of 2.

This was a very simple example, but imagine you are looping over a dynamic set of data that should each return a clickable element. You could then pass an index or and id or some other variable to identify the element.

Ultimately, this is just a pattern for function reuse. There are other ways to accomplish the same level of abstraction like using inline functions, but this is just for the sake of explaining currying and how it may be used.

simply this is whats happening when the code first run

const MyComponent = (props) => {
  const onClickHandler = (somearg) => (e) => {
       console.log(`somearg passed successfully is ${somearg}`)
  };

  return (
    <div onClick={onClickHandler('some args')}>
    </div>
  );
};
  1. When it sees onClick={onClickHandler(1)} it will run the code inside the onClick

  2. Then onClickHandler is a function and we pass an argument as 1 and execute it, now it will return a another function with replaced values as below.

    (e) => {
        console.log(`somearg passed successfully is 1`); // see args gets replaced with the value.
    }  
    
  3. so now when we click on the div above function will be called.

to make sure this is what exactly happening see the below Demo

const MyComponent = (props) => {
   const onClickHandler = (somearg) => (e) => {
       console.log(`somearg passed successfully is ${somearg}`, new Date().getTime())
   };

   return (
        <div onClick={onClickHandler(new Date().getTime())}>
           div
        </div>
   );
};

and you will see the times are different, which means clicked time and function created time is different.


So if you are put a one function inside onClick as it will gets executed with the code executing, and will not respond to you clicks

const MyComponent = (props) => {
    const onClickHandler = (e) => {
       console.log(`somearg passed successfully is`, new Date().getTime())
    };

    return (
       <div onClick={onClickHandler(new Date().getTime())}>
          div
     </div>
    );
};
Related