I believe this teardown function runs on unmount whether or not the dependency array is empty.
I believe this teardown function runs on unmount whether or not the dependency array is empty.
This kind of goes towards my point. useEffect works, and it works great. It's flexible and powerful - but it's cryptic as hell, and the interface is just "memorize it because you have to", not something more intuitive.
What if useEffect required a 2nd argument, but you had the option to pass in self, which would still offer the onMount behavior, by mirroring the way the other form of it worked? Bada-bing, now there's no exception to the rule. What if the 2nd argument was a named argument, like "trigger"? Now it's self-documenting. What if the teardown function as an optional 3rd argument with a name, too? Now it's easy to glance at a useEffect and tell whether it's declaring a teardown without carefully reading the body. etc etc.
He says "useRef offering a connection to DOM elements is just sugar", but that's not sweet, to me. There's no reason one thing should do two totally different things. That's exactly what I'm complaining about.
For many projects it felt like it gave you super powers, for some it was just OK, and a small percentage of interfaces just didn't fit the React model and were better some other way.
It appears to me that since then that small percentage has gotten the development attention (understandably), creating a React which is more well rounded and broadly useful but there is more to learn and the super power feeling has been dulled a bit.
Overall it has improved but I still wonder what a React that was more specialized for those interfaces where it really works great would be like.
I definitely agree useEffect is awfully cryptic and easy to get wrong, and I'm happy to be corrected... but I'm not sure how I'm wrong about it running on every render when there's no 2nd argument?
I kinda wish they'd made it easier to do the common operations like onMount and onUnmount by providing some simplified wrappers around useEffect (with less power comes less responsibility... or something). Of course we can make custom hooks for those, but having the well-trodden paths be paved is always nice.
Of course, it does run on unmount when the dependency array is empty, and it runs on unmount when there are dependencies in the dependency array.
But upon re-reading what you said, I think your intent was that it's comparable to componentWillUnmount() in class-based React only when the dependency array is empty (because otherwise the cleanup function also gets called when dependencies change).
My apologies, as I never really used class-based React, so the distinction was lost on me (and also forgot about the cleanup function being called between useEffect callback calls)
If anything it’d be weirder to make this two separate concepts. What would they even be? What does a ref not already do, as a box that contains an arbitrary value, that we’d want from a box with an element in it?
edit: I'm wrong, the cleanup is also called when dependencies change, just not on mount.. eg. it gets called before the effect callback being called again.
In other words, the cleanup function is called on unmount when useEffect is called with an empty array, and if useEffect has dependencies, it will also be called when those dependencies change