1

In my component, I have:

<StyledPill
    key={`styled-pill-${idx}`}
    size="small"
    label={searchType.label}
    onClick={() => handleClick(idx + 1)}
    featured={selectedSearchType === idx + 1}
/>

where:

const handleClick = (index: number) => {
    setSelectedSearchType(index);
};

However, I was told that we don't want to have anonymous functions () => handleClick(idx + 1). Is there some performant way to avoid it?

I can't do onClick={handleClick} because then I can't pass the argument.

Looking for some help - any would be appreciated. Thanks!

0stone0
  • 34,288
  • 4
  • 39
  • 64
Shamoon
  • 41,293
  • 91
  • 306
  • 570

4 Answers4

3

You can avoid creating an anonymous handler for each element by making the per-item data available on the element, and reading it in the event handler.

However, this is a premature optimization that you probably don't need.

function Component({ searchTypes, selectedSearchType, handleClick }) {
  const handleItemClick = React.useCallback((event) => {
    const itemId = parseInt(event.target.dataset.index);
    handleClick(itemId);
  }, [handleClick]);
  return (
    <>
      {searchTypes.map((searchType, idx) => (
        <StyledPill
          key={`styled-pill-${idx}`}
          size="small"
          label={searchType.label}
          data-index={idx + 1}
          onClick={handleItemClick}
          featured={selectedSearchType === idx + 1}
        />
      ))}
    </>
  );
}
AKX
  • 152,115
  • 15
  • 115
  • 172
2

Hmm, if you really would like to do it and have access to the StyledPill component, an option could be to accept onClick and index as props, then write a wrapper function to call the onClick with the index.

<StyledPill
    key={`styled-pill-${idx}`}
    size="small"
    label={searchType.label}
    onClick={handleClick}
    index={idx + 1}
    featured={selectedSearchType === idx + 1}
/>
// StyledPill.jsx

function StyledPill({onClick, index}) {
    function handleOnClick() {
        onClick(index);
    }
    
    return (
        <button onClick={handleOnClick} .../>
    )
}
Preet Mishra
  • 389
  • 3
  • 7
  • And if you don't have access to the `StyledPill` component (for instance it is created with `styled-components`), you'd have to create a wrapper component. – Guillaume Brunerie Sep 06 '22 at 13:55
  • This will still create a `handleOnClick` per `StyledPill`. No improvement. – AKX Sep 06 '22 at 13:58
1

You could achieve that like this, which is also called point-free style

const handleClick = (index: number) => () => {
    setSelectedSearchType(index);
};

// ...

<StyledPill
    key={`styled-pill-${idx}`}
    size="small"
    label={searchType.label}
    onClick={handleClick(idx + 1)}
    featured={selectedSearchType === idx + 1}
/>

Codesandbox Demo

Edit hopeful-northcutt-2ucy4q

hgb123
  • 13,869
  • 3
  • 20
  • 38
  • 1
    This won't work, since you're now calling `handleClick` immediately. – AKX Sep 06 '22 at 13:50
  • In `Vue` this would be possible, but not `React` – Konstantin Sep 06 '22 at 13:50
  • https://stackoverflow.com/questions/48699573/correct-use-of-arrow-functions-in-react – 0stone0 Sep 06 '22 at 13:51
  • @AKX Since you said that it would not work, I have made an example, please find it here https://codesandbox.io/s/hopeful-northcutt-2ucy4q?fontsize=14&hidenavigation=1&theme=dark – hgb123 Sep 06 '22 at 13:58
  • @Konstantin please check the example https://codesandbox.io/s/hopeful-northcutt-2ucy4q?fontsize=14&hidenavigation=1&theme=dark – hgb123 Sep 06 '22 at 13:58
  • 2
    Well, for one, you edited the code since my comment, so okay, it does work. Secondly, this still creates new functions, so it's the same thing as the original, but with one named function more. – AKX Sep 06 '22 at 13:59
1

If you just want to pass a named function to the onClick handler you could define the function inside your map() callback:

function Component({ searchTypes, selectedSearchType, handleClick }) {
  const handleClick = (index: number) => {
    setSelectedSearchType(index);
  };

  return (
    <>
      {searchTypes.map((searchType, idx) => {
        const handlePillClick = () => handleClick(idx + 1);

        return (
          <StyledPill
            key={`styled-pill-${idx}`}
            size="small"
            label={searchType.label}
            data-index={idx + 1}
            onClick={handlePillClick}
            featured={selectedSearchType === idx + 1}
          />
        );
      })}
    </>
  );
}
Camilo
  • 6,504
  • 4
  • 39
  • 60