1

So I have 4 components that are all doing the same thing inside an onClick handler.

I have to define this code in every single one of them.

The reason I don't know how to make this reusable is that you cannot call setUserContext inside a regular non-react utility function. I tried creating a hook but you cannot use Hooks as callbacks inside onClick.

What are my options here?

  const { userContext, setUserContext } = useContext(UserContext);

  // this goes inside onClick and is defined in like 4 components (too much repetition)
  const favoriteItem = (e) => {
    e.stopPropagation();
    e.preventDefault();
    setUserContext({ ...userContext, favoriteItems: JSON.parse(localStorage.getItem("favoriteItems")) });
  }
skyboyer
  • 22,209
  • 7
  • 57
  • 64
SoGoddamnUgly
  • 706
  • 4
  • 9

1 Answers1

1

You can create a custom hook.

const useCustomHook = () => {


const { userContext, setUserContext } = useContext(UserContext);

  const favoriteItem = (event, game) => {
    e.stopPropagation();
    e.preventDefault();
    setUserContext({ ...userContext, favoriteItems: JSON.parse(localStorage.getItem("favoriteItems")) });
  }

return { favoriteItem } 
} 


export default useCustomHook;

Your component can do this.

... 
const { favoriteItem } = useCustomHook() 

return (
<Element onClick={(event) => favoriteItem(event, game)} /> 
) 
... 
Mehul Thakkar
  • 2,177
  • 13
  • 22
  • Just check why we need `game` and what it is doing there. That'll help to cleanup the code as well. – Mehul Thakkar Sep 26 '21 at 04:04
  • its irrelevant and i removed it. I need to call this hook inside onClick handler so i dont think your example will work. – SoGoddamnUgly Sep 26 '21 at 04:08
  • I think it is still relevant you can remove the game as a dependency and call the same click handler from any function. You want a single click function just to not repeat the code right? You can't create a non-react util as you're using the `setContext` in there. – Mehul Thakkar Sep 26 '21 at 04:10
  • You don't have to call this hook inside onClick handler. You just have to import this in a component and pass it to the onClick. – Mehul Thakkar Sep 26 '21 at 04:12
  • You're moving your repeated code in a separate hook. I've updated the example. You can also create a separate component if the DOM is same and repeated. – Mehul Thakkar Sep 26 '21 at 04:14
  • Ok it turns out the game is relevant. How do i pass it in through the onClick? – SoGoddamnUgly Sep 26 '21 at 04:25
  • Updated the example. If you don't need an event you can remove that but if you need an event then you should pass both. Also, If it works consider accepting the answer as well. – Mehul Thakkar Sep 26 '21 at 04:34
  • No problem buddy! – Mehul Thakkar Sep 26 '21 at 05:25
  • I'd wrap `favoiteItem` method into `useCallback`. Not because of "extra re-render for PureComponent/React.memo" but because we may want that function in `useEffect` - and running effect on each re-render might be suboptimal. – skyboyer Sep 27 '21 at 13:54