Hacker News new | ask | show | jobs
by nop_slide 1691 days ago
Interesting, I mostly followed this approach which is to basically never use those constructs unless you are 100% certain you know what will happen.

https://kentcdodds.com/blog/usememo-and-usecallback

TLDR;

> Specifically the cost for useCallback and useMemo are that you make the code more complex for your co-workers, you could make a mistake in the dependencies array, and you're potentially making performance worse by invoking the built-in hooks and preventing dependencies and memoized values from being garbage collected. Those are all fine costs to incur if you get the performance benefits necessary, but it's best to measure first.

2 comments

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.

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.
> you could make a mistake in the dependencies array,

This is an auto-fix with eslint, and when it isn't exactly right (you need a "one way update") you can override that rule.

I would posit that passing a value that is regenerated every render (as opposed to when it actually changes) outside of the component (via props or context) is much more dangerous and likely to create infinite loops. For stuff that stays internal, sure, knock yourself out (until it is required by a useEffect or anything else that needs dependencies).