Hacker News new | ask | show | jobs
by jakelazaroff 1701 days ago
The problem with avoiding useCallback is that another hook will bite you: useEffect. If you need to define functions that interact with your component's state, you have to memoize them with useCallback (or useRef) to avoid a useEffect infinite loop.

What's even worse is that if functions passed as props are unstable, your useEffect will run every time the parent component renders — meaning that a component can't trust functions passed into it.

This is one of many reasons I think useEffect is a huge footgun, and I really wish we had a better primitive for causing side effects.

2 comments

I wouldn't say useEffect is a footgun, it just requires realising that React is doing shallow comparisons.
To me, a footgun isn't necessarily something that is hard to understand, but also something that's easy to misuse even if you understand it.
very good point
hooks in general are a huge footgun. You need to place them at the preamble of your function (and not nested). They have to be named with "use" prefix (worth mentioning is React basically commandeered the entire "use" namespace for their own purposes via lint enforcement, which will bite you in the ass eventually), and they are poorly designed.

Take useRef for example. You'd logically expect it to work with useEffect and that would be how you use refs in hooks land. But of course, refs are still a design wart on React (they've been through, what, 4 iterations now and they still can't figure out the interface?!). So of course you need to use useCallback. So what is the point of useRef then? I have no idea. The only use I've found is for "instance" variables. Or maybe onClick callbacks that run later. But now you have a ref that only works in some cases and not others. Yay, "composability"

Browse the React docs and you'll find the caveat-to-design ratio is exceedingly high. On any other project you'd assume this is beta or alpha ware.

In practice, I don't think the "rules of hooks" [1] are a footgun, especially if you use the eslint rule.

I'm confused about your second paragraph. useRef works perfectly fine for keeping a reference stable so as to avoid triggering useEffect. In fact, that's one of the main tools I use to work around the useEffect dependency array.

[1] https://reactjs.org/docs/hooks-rules.html

useRef can be used to hold a reference to DOM elements, useful for breaking out of Reactland or to hold and mutate values that should not cause a rerender.