11 ms·
Hooks are the worst thing to ever happen to React. They're so easy to get started with but every codebase I've seen adopt them has turned into complete untestab
by BreakfastB0b 6y ago
Hooks are the worst thing to ever happen to React. They're so easy to get started with but every codebase I've seen adopt them has turned into complete untestable spaghetti.
Mixing stateful effectful code inside what would otherwise be a pure declarative render function leads to so much complexity in an attempt to bridge the two paradigms. Junior engineers are also constantly tripped up by the subtleties of `useEffect` and `useState`.
Furthermore I think attempting to "encapsulate" side effects is a bad approach to writing testable programs. Most React components that use hooks end up having several chains of promises inside them but no way to await the final promise meaning tests have to be full of
await wait(0)
await wait(0)
await wait(0)
God forbid someone comes along and tries to be clever and replaces it with
await wait(3)
which now makes the test non-deterministic.
Cycle.js is the only framework that seems to get this right by acknowledging that a component doesn't just output JSX, but actually outputs JSX, HTTP Requests, etc.
Look, I get that Redux was a pain in the ass with all the boilerplate, but how did we throw the baby (unidirectional data flow) out with the bathwater. I no longer advertise that I know frontend development because the entire react community seems to have lost its mind.
- eitland 6y agoI haven't used React and React hooks as long as I have used Java and Maven, but consider this: If many successful people voluntarily use something you cannot understand there is always the possibility that you are the one who are missing out on something. (FWIW: I've been there myself)
- sbergot 6y agoI have used them on a medium project. I enjoy them very much but I have seen a lot of people struggle with the "rules of hooks"* I can see why some people prefer to use classes where the design is cleaner (even though you are more limited). *: https://reactjs.org/docs/hooks-rules.html#:~:text=Only%20Call%20Hooks%20at%20the%20Top%20Level&text=Instead%2C%20always%20use%20Hooks%20at,multiple%20useState%20and%20useEffect%20calls https://reactjs.org/docs/hooks-rules.html#:~:text=Only%20Cal....
- presentation 6y agoIf you use a linter though you can just auto enforce all the rules and back to it being just fine. An extra setup step but tools like create react app bundle ESLint for you already so I don’t mind it.
- yeneek 6y agoA lot of successful people use Cobol too
- BreakfastB0b 6y agoI absolutely acknowledge this is a possibility, but I think I do understand why people use it. Because they're easy, hooks are just so god damn easy to use. Want some state? Just chuck in a `useState` and call it day. But the problem is, they're not simple, and that complexity will grow and grow until it makes the app unmaintainable. I've seen this happen at three different companies I've worked at.
- xwdv 6y agoOne thing you are missing is a lot of organizations don’t care about UI tests. They’re brittle and the UI is always changing anyways so you get diminishing returns from writing many of them. Usually an end to end test is enough. UI logic is usually not that complicated, if it doesn’t work you will know right away. Hooks are acceptable.
- nicoburns 6y agoTo me the main benefit isn't that they're easy, it's that they're composable. They allow you to reuse "business logic" in multiple components. If it's getting too complex then that's presumably when you ought to be creating a custom hook which wraps up some of that complexity.
- valenterry 6y agoI'm not familiar with react hooks, but when I read what you write, my immediate reaction is: we already have a way to reuse business logic. It's called functions. Define a function and use it, either a global static function or pass it down to the component if you want to mock it. Reading the react docs, I find this part interesting: > Hooks were designed with static typing in mind. Because they’re functions, they are easier to type correctly than patterns like higher-order components. Importantly, custom Hooks give you the power to constrain React API if you’d like to type them more strictly in some way. React gives you the primitives, but you can combine them in different ways than what we provide out of the box. (https://reactjs.org/docs/hooks-faq.html#do-hooks-work-with-static-typing https://reactjs.org/docs/hooks-faq.html#do-hooks-work-with-s...) Seems to me as if hooks try to fix the lack of a good programming language. These approaches usually go wrong eventually. Maybe it's time to ditch Javascript (and even Typescript) and use a proper language (purescript maybe?) so that all these things can be done with just functions.
- dbbk 6y agoI actually think the problem is a lack of critical thinking. When Hooks were announced by Dan Abramov, people were hailing him as a genius etc, that this was a panacea.
- knuthsat 6y agoI think hooks and effects are really good. You can test them separately. You can write global reactions to state changes very easily. I find hooks/effects better than mobx or redux. hooks/effects, redux, mobx would be my preference order. Although redux works so well that it can be used with hooks/effects. For global state I would just use a React.Context with it's own effects. Most components do not have any async effects. I do admit that when jumping into a new codebase with hooks/effects I often find people have just butchered the concept. But I find that when I jump into codebases with mobx and redux too. The butchering that people do with mobx is much worse, with massive module importing of global stores, misuse of `name?: type` inside stores because they want to initialize the store at a later time.
- BreakfastB0b 6y agoYou can write global reactions to state changes very easily. This is exactly the problem, shared mutable state leads to "spooky action at a distance". It results in causal connections between parts of your codebase that are not reflected in the control flow of your code. If you have immutable unidirectional data flow causal relationships between parts of your code base must be reified in the control flow of the language. Most components do not have any async effects. At least when using Apollo / GraphQL almost every component ends up with async effects. I think this talk by Andre Staltz is the best explanation and solution of the problem https://www.youtube.com/watch?v=SXdtrhn8iII https://www.youtube.com/watch?v=SXdtrhn8iII
- knuthsat 6y agoBut the state is not mutable, the state is inside a React.Context that provides functions that manipulate it. It's practically the same as redux. You still need to have async actions with redux and use these actions. mobx on the other hand is exactly that, the state is globally mutable, anyone can import it from anywhere to anywhere.
- postalrat 6y agoIMO the new context and hook are the best thing that react has done. Hats off to whoever designed them.
- yeneek 6y agoHappy that someone other than me sees that too. I predict that companies will start leaving React in 5 years. React will have the same fate as AngularJS and jQuery.
- onion2k 6y agoJunior engineers are also constantly tripped up by the subtleties of `useEffect` and `useState`. They are, but they're also tripped up by the subtleties of class-based React components. The difference is that with hooks it's really obvious when they've tripped up (because React can tell, and warns you) while with classes it's really not obvious at all. This is one place where hooks are a clear win.
- azangru 6y ago> Junior engineers are also constantly tripped up That's just the nature of being a junior engineer — you get tripped up. Tripped up by mutating objects, by stale closures, by comparing numbers to strings, by asynchrony, by thinking in terms of rxjs or xstream streams, by god knows what else.
- fn1 6y agoSo let's write code in a way that doesn't trip up junior engineers... That will also help seniors when they are tired or under time-pressure.
- true_religion 6y agoSure and if you are at a big company like Facebook that makes total sense. However lots of us work for smaller firms. My company has no junior engineers.
- warent 6y agoIs there anybody that develops on the frontend professionally fulltime and makes these kinds of complaints? It seems like these are always drawn up by backend developers who lob fistfuls of aggression-poop over the fence for reasons beyond my fathoming, or junior developers (or UI folks who occasionally use javascript) that find it easier to trash on patterns rather than learn about them. I have used React professionally for years and get the skepticism around hooks. It seemed really stupid to me before I learned about it. Why change what wasn't broken? Now after learning about it I'll never go back to class components if it can be avoided and happily recommend hooks to all my clients who also end up loving them. No idea what this promise chaining thing is that you're talking about. Sounds like a bad design pattern that has nothing to do with hooks. No idea why you're suggesting Redux has anything to do with hooks. They're completely different. This meme is dead. Only a superficial understanding of React, or ingrained bad programming pattern habits, keep this meme alive.
- presentation 6y agoI agree, the main issue that I’ve had is just that its easy for (usually junior) devs to accidentally make infinite loops with interdependent state + effect hooks. But besides that I would never go back to class components.
- timhwang21 6y agoI've more or less driven frontend development with React at several companies over the last 4 years. While some of the complaints are exaggerated I don't think the overarching premise should be dismissed as "a meme." > No idea what this promise chaining thing is that you're talking about. If you have any asynchronous things going on in `useEffect`, you'll have to do something similar to that `await(0)` song and dance in tests. This specifically affects tests if you do things like update the UI by toggling loading spinners on await. > Redux s/Redux/higher order components. One of the motivations for hooks was that as a mechanism for logic composition, HOCs just felt awful to use. (So did render props, which everyone suddenly used for everything in a brief moment of collective insanity.) > Only a superficial understanding of React I think there's something in this. The fact is that good or bad, 1) hooks aren't intuitive, 2) hooks have basically doubled React's API surface area. Previously, React was so simple that a backend engineer could pick it up and get productive with it in half a week. That's much less the case these days. I've been onboarding devs to React for years, and these days there's a lot more "yeah, that's magic, you don't need to know how that works for now."
- ljm 6y agoThe problem I see with hooks is how they replace one set of problems with another, and demand you structure your code in a way to avoid those pitfalls. You know, how to structure conditional code, how to use loops when dealing with hooks, having to think about function object equality, having to supply the functions and variables your callback/effect closes over as dependencies (I still don't understand why you would do some of that in favour of pulling your callback out of the component)... and for what? For it all to change in another year or so when the JS community starts hankering for another paradigm? Lately when working with all this I feel as if the same code would be simpler and easier to follow if it wasn't shoehorned into JS. It's like the uncanny valley of functional programming. But more fundamentally, dealing with frontend application code is mentally exhausting in a way I haven't experienced before. I feel like I'm no longer learning Javascript as a language, but just keeping up with the novel abstraction of the month. I should add that I don't hate it, and there's plenty still to appreciate. Some of it is a joy and it's refreshing to work on projects that embrace more functional styles over the typical CRUD and OOP taxonomy construction you get in a typical backend job. Different set of problems once you get away from the typical framework stuff (react, redux, saga boilerplate).
- wongarsu 6y agoI feel like that's more a complaint about the JS frontend ecosystem as a whole. Every paradigm has its own pitfalls and idioms, and at least to me hooks seem better than class components most of the time. You exchange one set of pitfalls with another, and get more pleasant, more composable behavior overall. But compared to many GUI frameworks in other languages it still feels like a mess, and it's a mess that constantly changes from under you.
- ljm 6y agoYou're absolutely right. The native platforms aren't perfect, but they're stable and successful.
- joekrill 6y agoHooks are not some panacea that's going to fix a defunct development process or poor code organization and management. Any codebase, using any language, framework, feature, and technology, needs to be managed properly. There's really no getting around that. And without that, you're almost always going to end up with things turning into something along the lines of "complete untestable spaghetti". Especially when you have junior developers involved. Hooks are no different, nor is the entire Javascript landscape. In general these complaints are getting tiring and often feel like they are coming from folks who don't have the appropriate level of experience or knowledge in a particular subject area to be making these generalizations. I don't know what your level of competence is, but this line: > Look, I get that Redux was a pain in the ass with all the boilerplate, but how did we throw the baby (unidirectional data flow) out with the bathwater. gives me pause, because Hooks aren't meant to replace Redux in any way. There are hooks that maintain state, sure, but generally they're meant to replace class component lifecycle functions. Hooks and Redux still coexist quite well.
- qudat 6y agoAs someone who architects FE codebases for a living I both agree and disagree with you. React hooks definitely threw a wrinkle in the testability of react components. However, the ideas around how the FE should be tested has changed to the point where current thinking is that integration tests are the most valuable tests you can write. Testing what a react component does in isolation of redux or its side-effects is easy to do and also not incredibly useful. Furthermore, many modern codebases still use redux. I still advocate for it. Using hooks and redux are not mutually exclusive. I wish there was something better than hooks, it’s very easy to forget a dependency or get into infinite loops, but they do make life much easier. No more mapStateToProps or mapDispatchToProps HoCs. No more “smart” vs “dumb” components. No more function/class components. There’s only one component. Also, we are seeing an increase in “headless” react libraries, where the logic of some functionality is disconnected from the visual design of a set of components. It makes composition, extendability, and maintainability much easier.