I have been reading a bunch of React code and I see stuff like this that I don't understand:
handleChange = field => e => { e.preventDefault(); /// Do something here }
An easy way to grasp this is to remember that a curried/double arrow function is a function that implicitly returns another function(s). Going by this logic, you could also have triple arrow functions and so on.
In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever. With arrow functions the this keyword always represents the object that defined the arrow function.
Arrow function is one of the features introduced in the ES6 version of JavaScript. It allows you to create functions in a cleaner way compared to regular functions. For example, This function // function expression let x = function(x, y) { return x * y; }
What It Is. This is an arrow function. Arrow functions are a short syntax, introduced by ECMAscript 6, that can be used similarly to the way you would use function expressions. In other words, you can often use them in place of expressions like function (foo) {...} .
That is a curried function
First, examine this function with two parameters …
const add = (x, y) => x + y add(2, 3) //=> 5
Here it is again in curried form …
const add = x => y => x + y
Here is the same1 code without arrow functions …
const add = function (x) { return function (y) { return x + y } }
Focus on return
It might help to visualize it another way. We know that arrow functions work like this – let's pay particular attention to the return value.
const f = someParam => returnValue
So our add
function returns a function – we can use parentheses for added clarity. The bolded text is the return value of our function add
const add = x => (y => x + y)
In other words add
of some number returns a function
add(2) // returns (y => 2 + y)
Calling curried functions
So in order to use our curried function, we have to call it a bit differently …
add(2)(3) // returns 5
This is because the first (outer) function call returns a second (inner) function. Only after we call the second function do we actually get the result. This is more evident if we separate the calls on two lines …
const add2 = add(2) // returns function(y) { return 2 + y } add2(3) // returns 5
Applying our new understanding to your code
related: ”What’s the difference between binding, partial application, and currying?”
OK, now that we understand how that works, let's look at your code
handleChange = field => e => { e.preventDefault() /// Do something here }
We'll start by representing it without using arrow functions …
handleChange = function(field) { return function(e) { e.preventDefault() // Do something here // return ... }; };
However, because arrow functions lexically bind this
, it would actually look more like this …
handleChange = function(field) { return function(e) { e.preventDefault() // Do something here // return ... }.bind(this) }.bind(this)
Maybe now we can see what this is doing more clearly. The handleChange
function is creating a function for a specified field
. This is a handy React technique because you're required to setup your own listeners on each input in order to update your applications state. By using the handleChange
function, we can eliminate all the duplicated code that would result in setting up change
listeners for each field. Cool!
1 Here I did not have to lexically bind this
because the original add
function does not use any context, so it is not important to preserve it in this case.
Even more arrows
More than two arrow functions can be sequenced, if necessary -
const three = a => b => c => a + b + c const four = a => b => c => d => a + b + c + d three (1) (2) (3) // 6 four (1) (2) (3) (4) // 10
Curried functions are capable of surprising things. Below we see $
defined as a curried function with two parameters, yet at the call site, it appears as though we can supply any number of arguments. Currying is the abstraction of arity -
const $ = x => k => $ (k (x)) const add = x => y => x + y const mult = x => y => x * y $ (1) // 1 (add (2)) // + 2 = 3 (mult (6)) // * 6 = 18 (console.log) // 18 $ (7) // 7 (add (1)) // + 1 = 8 (mult (8)) // * 8 = 64 (mult (2)) // * 2 = 128 (mult (2)) // * 2 = 256 (console.log) // 256
Partial application
Partial application is a related concept. It allows us to partially apply functions, similar to currying, except the function does not have to be defined in curried form -
const partial = (f, ...a) => (...b) => f (...a, ...b) const add3 = (x, y, z) => x + y + z partial (add3) (1, 2, 3) // 6 partial (add3, 1) (2, 3) // 6 partial (add3, 1, 2) (3) // 6 partial (add3, 1, 2, 3) () // 6 partial (add3, 1, 1, 1, 1) (1, 1, 1, 1, 1) // 3
Here's a working demo of partial
you can play with in your own browser -
const partial = (f, ...a) => (...b) => f (...a, ...b) const preventDefault = (f, event) => ( event .preventDefault () , f (event) ) const logKeypress = event => console .log (event.which) document .querySelector ('input[name=foo]') .addEventListener ('keydown', partial (preventDefault, logKeypress))
<input name="foo" placeholder="type here to see ascii codes" size="50">
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With