AncientSwordRage
AncientSwordRage

Reputation: 7618

useCallback with args passed in

I have a <Tabs /> component in material-ui, that has a handler for changing mode. The on change has this signature (from the link):

Signature:
function(event: object, value: any) => void
event: The event source of the callback
value: We default to the index of the child (number)

My implementation goes a little something like this:

<Tabs
  value={mode}
  onChange={handleChange}
/>
  <Tab id="choice1" value="one" label="Choice 1" />
  <Tab id="choice2" value="two" label="Choice 2" />
</Tabs>

My handleChange function is just an arrow fn around a useState-like hook

const handleChangeMode = (event, newMode) => {
  setMode(newMode);
}

In an effort to avoid recreating this arrow fn each time, I've tried to do this:

const handleChangeMode = useCallback((event, newMode) => {
  setMode(newMode);
}, [setMode]);

but I noticed, that the thing that changes the most, the new mode isn't part of the deps, and thus would perhaps not behave properly? Then I conjured this monstrosity from my darkest dreams:

const handleChangeMode = useCallback((event, newMode) => {
  useCallback(() => setMode(newMode), [setMode, newMode])();
}, [setMode]);

It's callbacks all the way down.

Previously, this question (React hooks useCallback with parameters inside loop) suggested not to use useCallback in that scenario. But as this is something that could be called over and over, it seems like the place to do so. Also the example with useMemo doesn't get around that I want to depend on a variable passed into the hook, which I don't even think works in this example (e.g. I'm using the hook wrong, as well as not knowing how to use it for my example).

How do I get around this issue?

(Edit: in fact, I cannot nest the callback/memo hooks at all. so the last code example doesn't work, as I suspected)

Upvotes: 2

Views: 5926

Answers (1)

Andrii Golubenko
Andrii Golubenko

Reputation: 5179

You ask:

but I noticed, that the thing that changes the most, the new mode isn't part of the deps, and thus would perhaps not behave properly?

const handleChangeMode = useCallback((event, newMode) => {
  setMode(newMode);
}, [setMode]);

Answer: No, this code will behave properly. You need to add props to dependencies only if you use them directly from component. For example:

const { mode } = props;
const handleChangeMode = useCallback((event) => {
  setMode(mode);
}, [setMode, mode]);

In your case you get newMode as argument of a function. So you don't need to add it as a dependency.

Upvotes: 3

Related Questions