> Hooks are the antithesis of this - they create code them seems pure
I disagree. The presence of a hook is the indicator that something impure is happening. Seeing a hook should be equivalent to seeing a promise, option, IO type etc.
Hooks also compose beautifully together. You can make so many great new hooks by combining just useState and useEffect together, bundling up that functionality into a new hook that you can then use in any UI.
> The presence of a hook is the indicator that something impure is happening.
Yes. And that's my whole point.
React was very powerful when care was taken to place impure code into a single class based component, that then passes state down to pure components as props.
React is a lot less powerful when developers scatter hooks everywhere.
New developers no longer have to go out of their way to understand the render lifecycles of a class based components, and feel the pain of writing componentDidMount or componentWillMount or componentWillUnmount or shouldComponentUpdate functions. Instead they just throw a hook in. Which is mostly ok - but it's hiding that you do actually still have to care about how this whole shindig works (and opens up a whole new world of pain around identity and equality checking, re-render cycles, dependency passing, etc)
I'm not saying hooks don't have an upside (ex: I'm right there with you, I mostly prefer a hook to an HoC from a reusability stand point) but hooks let developers shove their head into the sand and mostly pretend that they're writing a pure function - and they're ABSOLUTELY NOT.
There was nothing preventing you from scattering state everywhere in class based components. On top of this the component tree became a huge mess of HoC's stacked on top of each other.
You absolutely should not be scattering hooks everywhere in your code base. The same principle applies to use them higher in the hierarchy and pass down props.
This is a simple principle that can be taught to a new React developer. Keep your state at the highest level it makes sense to no matter the state mechanism used.
Hooks allow for composition of effects in a way that class based components did not.
> There was nothing preventing you from scattering state everywhere in class based components.
There was though - it's the same pain you're referring to later... "Hooks allow for composition of effects in a way that class based components did not."
Class based components sucked in a lot of ways. But the nice side effect of that was that folks tended to use them more carefully, and avoid using them when they didn't understand them (or at least avoid implementing any method besides render()).
I'm not saying hooks don't have nice properties - I'm saying that I'm not convinced (after using hooks for about 2 years now) that the price you pay is worth it.
The number one source of bugs in our codebase is... drumroll... hooks. I think a part of that is that state in general is evil, and will be where most of the bugs lurk. But I think the other side is that hooks have a completely new, unintuitive, hard to reason about set of rules. Composable? Sure, sometimes, if you work really hard to understand exactly what sort of new rules you're creating and then hiding in their complexity. Intuitive? Fuck no!
We can just agree to disagree then. I'd find libraries all the time on github which had class components using state in weird ways you wouldn't expect.
It sounds like your org could use some simple guiding principles and code reviews. You seem experienced, this shouldn't be a big problem. Maybe help guide your junior devs?
Eh - I'm not really sure we're even disagreeing. I just think that hooks let you stack the abstraction tower a lot higher, and answering some fairly basic questions can become really hard.
There's power there, and I absolutely agree that hooks do a better job of making for re-usable code than HoCs, I just think that the general level of understanding for them is low, and most devs do a really poor job reasoning about them (and in generally - I find they're basically impossible to reason about in isolation).
I see people do things like wrap everything in useMemo and useCallback, or pass complex objects to useEffect as deps, or fail to understand that making the output of useState the dependency of a useEffect hook that happens to call the corresponding setState function is a recipe for lockups, or any number of other fairly simple mistakes.
Plus... tools like redux strongly encourage destructuring semantics, and destructuring for hooks is absolutely the wrong thing (for the same reason - equality and identity checks). But then you're in a conversation about object identity and memory locations with a dev who has never encountered a pointer in their life, who's 6 months out of a bootcamp, and whose eyes are glazing over further and further with every word out of your mouth.
Worse - hooks can give you a loaded gun if you expect all the environments your code runs in to act like a browser (see my useLocation example with JSDom). Works a-ok when tested in a browser. Will even work nicely for the specific tests you might write for your component (since folks generally mock their hooks) but will absolutely foot-gun you if another spec calls the real hook. Happens to eat up a boatload of CI cpu usage and time as well.
I disagree. The presence of a hook is the indicator that something impure is happening. Seeing a hook should be equivalent to seeing a promise, option, IO type etc.
Hooks also compose beautifully together. You can make so many great new hooks by combining just useState and useEffect together, bundling up that functionality into a new hook that you can then use in any UI.
reply