0

In the code snippet below, I'd like to move this function out of jsx and wrap into useCallback.

{suggestedTags.length ? (
          <div className={classes.tagSuggestionWrapper}>
            {suggestedTags.map((tag) => {
              return (<div key={tag} 
                          onClick={() => { selectTag(tag) }}>{tag}</div>
                          );            
            })}
          </div>
        ) : null }

Otherwise, a new function is created for every element on every render.

I understand that this may complicate the code, and may not be advisable. But I have to do it. I ask for your advice

Paul
  • 53
  • 3
  • 21
  • Moving the `.map` function outside the jsx will have no advantage whatsoever even if you wrap it with `useMemo` or `useCallback`. What is the reason you want to do it? If the array is too large, try pagination or lazy loading. – Sinan Yaman Jun 24 '22 at 07:31
  • @SinanYaman Because new function is created for every element on every render. – Paul Jun 24 '22 at 07:33
  • Do you mean the `() => {selectTag(tag)}` function? I thought you meant `.map` function. What is the problem when you try to wrap `selectTag` with `useCallback` with an empty dependency array. What have you tried so far? – Sinan Yaman Jun 24 '22 at 07:33
  • @SinanYaman Yes, () => {selectTag(tag)} – Paul Jun 24 '22 at 07:36
  • What is wrong when you try doing `const selectTag = useCallback((tag) => {...}, [])` – Sinan Yaman Jun 24 '22 at 07:37
  • [This question](https://stackoverflow.com/questions/64134566/should-we-use-usecallback-in-every-function-handler-in-react-functional-componen) is worth reading. You may not get your expected optimization. – Sinan Yaman Jun 24 '22 at 07:38
  • 1
    @SinanYaman Yes, I may not get the desired optimization, but I want to try useCallback in action on my code (I'm new to Javascript and trying to figure out a lot of things) – Paul Jun 24 '22 at 07:41

1 Answers1

1

You can do:

 const selectTag = useCallback((tag) => {
      setTags((prevState) => [...prevState, tag]);
      setSuggestedTags([]);
      setInput("");
    }, [])

Little about useCallback

Bare in mind that if you had used any state variable, or prop, you should have included that in the dependency array. An empty dependency array makes sure selectTag reference will stay the same once the component mounts.

And no dependency array is the same as not using useCallback at all

Removing the arrow function

You can remove the arrow function by passing the value by using the onClick event function:

   const selectTag = (event) => {
      const tag = event.target.name
      setTags((prevState) => [...prevState, tag]);
      setSuggestedTags([]);
      setInput("");
    }

    return (
      
        {suggestedTags.length ? (
              <div className={classes.tagSuggestionWrapper}>
                {suggestedTags.map((tag) => {
                  return (<div key={tag}
                              name={tag}
                              className={classes.tagSuggestion} 
                              onClick={selectTag}>{tag}</div>
                              );            
                })}
              </div>
            ) : null }

      </div>
    );
Sinan Yaman
  • 5,714
  • 2
  • 15
  • 35
  • Thank you! I will take a look at your recommendations. And tell me, how should my return look like in this case? – Paul Jun 24 '22 at 08:12
  • See the updated answer to remove the arrow function. As I said you don't need the `useCallback` :) Just added the first part since you said you wanted to experiment with it – Sinan Yaman Jun 24 '22 at 08:25
  • In addition you can see [this question](https://stackoverflow.com/questions/72736573/how-can-i-prevent-extra-background-operations-when-i-change-an-state-in-react/) which I just answered to see the use case for `useCallback` – Sinan Yaman Jun 24 '22 at 08:28
  • if I use selectTag with useCallback and in return writing onClick={selectTag} - its nit work. I have error: Uncaught Error: Objects are not valid as a React child – Paul Jun 24 '22 at 08:49