14

Consider this example:

 let memoizedCb = React.useCallback(
    memoize((param) => () => someFunction(param)),
    []
  );

where memoize is from external library like "fast-memoize". Above code gives warning:

React Hook useCallback received a function whose dependencies are unknown. Pass an inline function instead

I found this thread which if we adapt to my use case would suggest this as solution (if I am not wrong):

const memoizedCb = React.useMemo(
  () => memoize((param) => () => someFunction(param)),
  []
);

What is the warning about? why does useMemo fix this problem?

NOTE: someFunction is defined outside the function component so it is not needed as a dependency.

Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
  • 1
    It's a linter warning, not an actual error. You can either ignore it, or use a pattern that doesn't trigger it (like the `useMemo` one you got from that github thread). – Jared Smith Nov 03 '21 at 19:56
  • @JaredSmith I see it is a linter warning I am trying to explain why there is no warning with `useMemo` though – Giorgi Moniava Nov 03 '21 at 19:56
  • Ask the people that wrote the eslint plugin. You are correct that the two are logically equivalent. Maybe the have the same rule, after all you are passing an inline function to `useMemo`. – Jared Smith Nov 03 '21 at 19:58
  • 1
    @JaredSmith Yeah thats why I got confused because the two seemed the same :) – Giorgi Moniava Nov 03 '21 at 19:58
  • useCallback already memoizes the function, so using another utility to memoize the inline function is redundant and unnecessary. – Derek Nov 03 '21 at 20:36
  • 1
    @Derek Nope this way you are achieving different functionality. – Giorgi Moniava Nov 03 '21 at 20:41
  • You're better off defining your memoized function outside the component itself then, especially if they have no dependencies on props or derived values created inside the component. – Derek Nov 03 '21 at 20:57
  • @Derek yeah but the question is not about that. – Giorgi Moniava Nov 03 '21 at 20:57
  • `react-hooks/exhaustive-deps` ESlint rule should be burned to ashes and spread over the ocean. – Mikhail Batcer Jul 14 '23 at 20:07

3 Answers3

15

It seems the warning is there because useCallback (and also useMemo see below) expect inline function as argument (don't know why though).

So in the solution from the question:

const memoizedCb = React.useMemo(
  () => memoize((param) => () => someFunction(param)),
  []
);

they used useMemo to imitate useCallback functionality while also passing an inline function to useMemo as the warning required:

React Hook useCallback received a function whose dependencies are unknown. Pass an inline function instead


That warning is not specific to useCallback, you get same warning if you just replace useCallback with useMemo in the first example:

 // For testing
 // Gives same warning
 let memoizedCb = React.useMemo(
    memoize((param) => () => someFunction(param)),
    []
 );
Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
7

As a more general explanation the below will produce a warning:

const someFuncWrap = (fn) => (e) => fn(e)
const memoizedFunc = useCallback(someFuncWrap(foo), [someFuncWrap, foo]);

Changing the useCallback to a useMemo with an inline function passes.

const someFuncWrap = (fn) => (e) => fn(e)
const memoizedFunc = useMemo(() => someFuncWrap(foo), [someFuncWrap, foo]);

This is because to parse the hook eslint needs to see it in the following form:

useMemo(() => foo, [foo]);
useCallback((bar) => foo(bar), [foo]);
sam
  • 1,005
  • 1
  • 11
  • 24
5

As far as I know, the useCallback expects an inline function. If you pass a returned function from another function, eslint won't be able to figure out what are the dependancies of the function, so it will show this warning.

Here I think, eslint is failing to determine the dependancies of somefunction and thus it cannot evaluate the react-hooks/exhaustive-deps rule because to evaluate this rule eslint should be able to identify is there any dependancy like state, props for the function passed to useCallback hook. So eslint is asking you to pass an inline function which it will understand and can evalute for lint rules.

Aldrin
  • 2,036
  • 15
  • 12