My one-liner event handler function for toggling check boxes state in ReactJS
Tags: functional, javascript, react
Published: 2020-08-22 10:08:10

I am a ReactJS developer for over three years and every time I write an event handler function, a fairy dies... or one developer 
scratches his head.

This is a post on how I shortened my toggling handler functions with the help of mathematics and utility libraries down to one line.

This is a typical ReactJS component which renders five names and each one is paired by a checkbox.

```react
const names = ["Gale", "James", "Kim", "Mindy", "Karen"];

export function Names() {
  const [selected, setSelected] = React.useState(names);

  const handleToggle = (name) => () => {
    //
    //
  }

  return (
    <fieldset>
      <legend>Names</legend>
      {names.map((name) => (
        <React.Fragment key={name}>
          <input
            checked={selected.includes(name)}
            id={name}
            onChange={handleToggle(name)}
            type="checkbox"
          />
          <label htmlFor={name}>{name}</label>
          <br />
        </React.Fragment>
      ))}
    </fieldset>
  );
}
```

The most logical thing to do in our `handleToggle` event handler is to check the `selected` array and if it `includes` the name then it should `filter` that out, else it should add it to the array.

And the implementation should look like this:

```react
const handleToggle = (clickedName) => () => {
  if (selected.includes(clickedName)) {
    setSelected(selected.filter((name) => name !== clickedName));
  } else {
    setSelected([...selected, clickedName]);
  }
};
```

This implementation is fine, it will pass code reviews any day due to readability.

But... I'm weird. 

What if we change the clicked name into an array instead of a string and... return the [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) of the two arrays?

For example, the symmetric difference of `["Gale", "James", "Kim", "Mindy", "Karen"]` and `["Gale"]` is `["James", "Kim", "Mindy", "Karen"]`. It works like our `filter`, right? 

Also the symmetric difference of `["James", "Kim", "Mindy", "Karen"]` and `["Gale"]` is `["James", "Kim", "Mindy", "Karen", "Gale"]` which works like our array concatenation.

The symmetric difference can also be expressed with the XOR operator and as soon as I've read XOR and been a fan of utility libraries I started using the `xor` utility function.

Then the handler started looking like this:

```react
// import xor from 'lodash/xor';

const handleToggle = (clickedName) => () => {
  setSelected(xor(selected, [clickedName]));
};
```

But like I said... I'm weird.

I read about `ramda` and `lodash`'s `fp` and got _curried_ away. 

Every utility function exported from those two modules has reversed arguments (iteratee-first data-last) which means it can be called like this:

```javascript
xor([clickedName], selected);
```

They are also auto-curried (did you catch the pun earlier?
) which means they can be written like this:

```javascript
xor([clickedName])(selected);
```

Which means if you pass the first function as an argument to the `setSelected` action it will be called with the `selected` state anyway because set state actions accept callbacks that are called with the previous state.

So my handlers look like this now:

```react
// import xor from 'lodash/fp/xor';

const handleToggle = (clickedName) => () => setSelected(xor([clickedName]));
```

What do you think?

Did you scratch your head?