question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[react-hooks/exhaustive-deps] should have special case for props callbacks

See original GitHub issue

react-hooks/exhaustive-deps attempts to be 100% accurate, and flags the following:

const c = useCallback((value: number) => {
    props.onChange(value);
}, [props.onChange]);         // <-- ERROR: Should be [props]

It helpfully recommends that we should do this:

const {
    onChange
} = props;

const c = useCallback((value: number) => {
    onChange(value);
}, [onChange]);

Unfortunately, I can’t bring myself to actually write my code this way. It adds pointless boilerplate code, makes my IDE “find usages” feature on my props send me through another level of indirection i have to follow, and i have this ugly object destructure inside every react component I write only for the callback props that is plain ugly noise.

I’ve been using this technique lately:

useCallback((value: number) => {
    props.onChange.call(null, value);
}, [props.onChange]);        // <-- now the linter is happy!

Which is a bit better, but still ugly, and sadly the autocomplete experience for the call arguments is much worse.

I understand that if I were to write something like car.drive() then the linter would be correct that I should depend on car since car is being passed as this to drive, and car might change.

But “props” specifically is different. No matter how hard I try, I cannot think of a legitimate case where someone would set a prop callback such that it is expecting the actual props as the this argument. It makes no sense, and all of the official react documentation explain how you should use “bind” or whatever so that you have a locked-down this (if this is even needed at all). And the react team apparently agrees with me here, because this very lint rule suggests to destructure the prop, which would anyway break any such code that expects to have props passed back as this!

Recommendation: the lint rule should treat any function call of the form props.xxx(...) such that the expected dependency is props.xxx (instead of props). Just to be clear: this should only be done specifically for props, any other “method” style function call on an object other than props should continue to be linted in the current way.

Thank you

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:11 (3 by maintainers)

github_iconTop GitHub Comments

4reactions
HenryCharlesAndersoncommented, Feb 2, 2021

Destructuring works fairly poorly if your props are a disciminated union, eg:

type Props = 
  | {
      kind: 'range'
      value: Date[]
    }
  | {
      kind: 'day'
      value: Date
    }
  | {
      kind: 'timer'
      value: number
    }
 // ...

Destructuring props breaks the discriminating union.

This is a rare enough usecase for me personally that I’m fine with disabling the lint rule, but I’d be interested to know if anyone has a better solution

3reactions
benny-medflytcommented, Apr 8, 2020

… I mean, you could do

interface ButtonProps {
  color: string;
  children: JSX.Element;
  onChange: () => void;
}

function Button({ color, children, onChange }: ButtonProps) {
  // ...
}

But with it ends up being way too much repetition for my tastes

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to correctly implement a props callback function in the ...
Adding handleChange as a dependency results in an infinite re-rendering loop. I've tried every solution I can find but must be missing something ......
Read more >
Dealing with callbacks as props in React - DEV Community ‍ ‍
In this case, pure components won't be re-rendered every time when their parent gets re-rendered. Especially, callbacks caching is effective to ...
Read more >
12 essential ESLint rules for React - LogRocket Blog
ESLint has a comprehensive set of rules for JavaScript code that cover stylistic choices and prevent common bugs. Using ESLint alone will ......
Read more >
How to manage the useEffect dependency array like a pro?
Useeffect dependency array: TL;DR. You should use react-hooks/exhaustive-deps eslint rule and refactor your code in this order:.
Read more >
What are dependency arrays in React? - Devtrium
If you want to use functional components in React, you'll have to deal ... So for example, for useEffect it means the callback...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found