Maybe, but in my experience whenever I encounter an incomprehensible mess of hooks it usually ends up because devs were not using all the tools that react provides.
For example a flurry of setStates could be wrapped up in one single state. If it gets too complex - into a reducer.
Components that don’t benefit much from splitting up could have their business logic wrapped into a context, and let the view code be just jsx without all the interweaving of code and templates.
Maybe the one benefit of classes was like it forced you to think in business logic, then render. React still has that, you just need to dive a bit deeper into its toolbox.
The result usually turns out much more flexible - contexts neatly wrap business logic for all of its descendants, classes don’t.
I think this was maybe because react actually allows you to write messy code, and it’s still performant and works. But in the end it just kinda postpones the inevitable maintenance burden.
I guess solid.js from the looks of it might postpone it a bit more. I just worry that solid looks more like magic, and some invariant somewhere will just break and I wouldn’t know what sequence of reactions actually led to that infinite loop that crashed the page. Haven’t tried it myself though, might more understandable in the end…
I can see both sides. I teach React to newish coders, and classes are easy for them to grasp...and then immediately create labyrinthine monoliths. At work where I do React, we emphasize small components with limited and segmented logic (ideally pulling as much logic out of the React parts as possible - and this is most easily done by avoiding classes).
At the same time, I've a passion for trying to make code more maintainable - which often means avoiding too much abstraction and keeping logic plain and up-front, where it can be found and followed, so I share some of your concerns.
But I'm excited about this. One of the best parts of React has been that the same logic that makes a good program makes for a good react app. Treat your components like functions (regardless of whether they are classes or not) - small, single purpose, decoupled from state - and you'll have an easier time. Hooks look to help that.
The sense I get is that the original React model has some pretty significant complexities, especially around shouldRender and prop / state analysis, and hooks present a big improvement on that.
I don’t think that the class-vs-function divide is the fundamental reason for the problems with the old model or the improvements with the new model. Rather, I think the learnings from the original approach informed the system and resulted in a step forward.
I find that once I need to manage a nontrivial amount of state, the functional model really feels wrong — useContext, I’m looking at you! And I wouldn’t be surprised if we end up with another turn of the crank that introduces a class-based (or prototype-based) approach with a better set of abstractions at some point down the line.
Agreed, after 6 years of use, my gripes with React come down to the re-rendering and lack of syntactic sugar for commonly used things. Hooks can get messy, but complicated components were complicated even with the class syntax.
What React has going for it, is that it is predictable. That is an extremely important part of any tool.
I would argue the inverse: if your project relatively simple enough that hooks don't feel messy, then it probably doesn't need to be a React app to begin with.
Class components are just (IMO) cleaner, and I find myself saddened at the level of disarray most codebases with hooks are nowadays. Enough has been written elsewhere about how hooks require one to keep more in their head; class components have an agreed up layout/structure/etc that is important in large codebases.
It’s a better representation of what’s going on underneath but FWIW I agree with you, there are very few instances where I find hooks code that’s as readable as class-based code.
I know I’m not typical at all but hooks kind of marked the point where I lost interest in keeping up with the changes in React. I’m lucky that my job doesn’t require me to, and I’ve had a great time exploring options like Vue and Svelte. Svelte in particular feels like it takes the opposite approach to hooks-based React: rather than force you to think about the way React is processing things it lets you write code the way you think about things and transpiles it into working JS.
Beyond “everyone uses it” I can find few reasons to prefer React these days.
All true. I work on a massive React codebase and it is a challenge to follow the logic because at any given time there could be a dozen effects firing off from a single state change. Granted, having the dependency array helps follow what's firing off, but when effects kick off other effects it gets into a mess. (Probably a sign that we should refactor some things) This problem isn't solved by class-based components either; years ago when I first started working on the codebase I found class-based components with gigantic componentDidUpdate() full of hard to follow conditionals and setting state. That said, hooks makes it easier to refactor problems like this in my experience.
I go back and forth on this - overall, I don't think hooks were a technical mistake (it's a fairly clean way to share code that is not cleanly shared in class components) but... I they accidentally knock a LOT of developers out of the pit of success. Overall - I think they accidentally made React apps a lot more unwieldy.
My sweet spot for React was when it was class based components mixed with purely functional components.
That combo led to all sorts of "happy accidents" in developer productivity. Logic that needed state tended to be clumped into a relatively small number of class based components, developers actively wanted to avoid adding state to new components because they had to write a lot more code to do it.
So you end up with a structure that looks like several small trees in the code: A single class based component managing the state for several pure function components under it. Overall - this was a fairly happy spot to be. State is contained, performance is usually pretty predictable, pure mappings are encouraged.
Hooks... well - they made state too easy again. Now adding state to a new component isn't a 20 line change (conversion to class). It's just dropping a new "useState()/useEffect()" call in near the top. Very easy. So easy you no longer really think about why that might not be such a great idea.
Now you end up with state creeping through the entire component tree. Renders are hard to predict because any parent component might re-render at any point, you're neck deep into useMemo and useCallback to try to prevent all those extra renders from really killing performance. This is not such a happy place to be.
Can those downsides be avoided? Of course. But developers no longer fall into the right path by default. You have to wrangle them there, and that's a huge downside.
I am "the react guy" -- but before that I built knockout applications with requirejs & angular applications with coffeescript and gulp, and before that with a 2000 line long script.js & jquery ;)
I don't really disagree with anything you said, except to point out that a lot of the current crop of web devs have never experienced what it is to build an app without any abstraction such as React, and quite understandably have no idea what problems it is doing for them.
I do know that since hopping onto react with all of that ~baggage~ context, I have never wanted to program UIs with a different model. It is true that hooks introduce a layer of abstraction that is sometimes difficult to reason about, but IMO they boil down the problems we faced with class components/lifecycle/server rendering gotchas, and put them front and center - forcing you to confront and fix them rather than settling for a solution that works 99% of the time.
I would totally disagree. We started migrating our front end to React this year. We dipped our toes in with Class based components, found out about hooks, and never looked back. Hooks are confusing when you're trying to translate a class based component to a functional component with hooks. Starting a component or page from the ground up with hooks is so, so much simpler than class based components. As with any iteration of any framework, there are gotchas, but they are no worse than Class based react (totally opinion there). The mental model, once you latch on to it, is so simple.
Fair enough. Though, the first question is - why does the component do so many things? Do they all need to be in a single component or can you break them apart?
For the cases when this is not possible, I agree, useEffect works better than classes lifecycle methods. But do you really want a system which caters to a small percent of use-cases at the expense of readability in others? And the improvement, to my eyes, is not that big anyway.
The hooks are my main gripe with React, but as the OP, I don't see a better alternative either - at least not one that would be worth a rewrite.
I was just going off my own experience with React through the years. It was very hard to compose behavior with class based components. We had to create higher order components that had functions as children which could pass down data as arguments to the child function. It really made a mess of the component hierarchy. Now you can create reusable custom hooks that can be used from any component.
The problem that hooks solve really nicely is when you want per-component state, but you duplicated versions of that state (and surrounding logic) in different components. With class-based React components you had to use things like higher order components, or manually add the state properties into each component. With hooks this is all neatly abstracted away.
You don't always need this. Sometimes your business logic can just be a pure function. But where you do (and IME this is quite common), hooks are super nice.
I feel like most production React I've seen already has a mixture of components written as classes versus ones written as functions versus functions and classes written to be HOCs. Adding Hooks in most codebases won't make most of them feel anymore "mixed" than they already were.
I really don't like hooks, because they are so magic. The old class based way of doing things was much more explicit. At least, hooks should take some kind of "context" and "name" parameters so that they are in spirit a pure function. Then you could also call them in loops and if blocks without problems.
Actually, class-based components have some annoying magic, too. The type of the object you create when you write `<MyComponent>` in JSX is different from the component class you write. There is some wrapper around it IIRC.
I wonder what React would look like if you get rid of all the cleverness and hidden state, and keep JSX and the reconciler as only magic?
All of this would be far more interesting to me if it weren’t based on React. Almost any other technological choice would have been better, from my perspective. I get it, React developers are cheap because people have bought into the React hype.
To me, though, especially with hooks, React creates a bizarrely deep object tree that is impossible to reason about in comparison with pretty much every other tooling that exists.
Having used React hooks for the past couple of months, I think I've come to the conclusion that I'm not going to recommend any body to switch away from class components.
I understand that hooks solve the problem of being able to compose side-effects and lifecycle in your components, but honestly, in the last three years of using React, I don't think I've ever actually had a scenario where hooks would have been a great solution for me. I'm not sure if this means I've been designing my React components very well, or very badly or what.
While hooks look like they might be good at some things (ex: useState is awesome), I think they come with too many subtle gotchas (the amount of literature on handling these gotchas, that's been written in the few months of hooks being in beta is mind-blowing) that I'd much rather just use class components.
The core of it is getting closer to true "reactive" programming. If you use hooks right™, you generally don't have to worry about how to handle values over time. React does all that plumbing for you (which is why we need all the dependency arrays).
This for me is the main advantage over class components. You don't need to worry about the various lifecycle methods (including having separate methods for componentDidMount and componentDidUpdate and making sure you do all the plumbing right when your parent changes props that you weren't expecting).
IMO, React really could have benefited from devoted language syntax for this (like Svelte does) to automagically and statically track all the dependencies. But React has an ethos of being "just JavaScript" (even JSX desugars to relatively straightforward React.createElement calls, and you can treat those nodes like regular JS objects, pass them around willy nilly, etc.), so it didn't happen (and instead we have lint rules like ESLint rules-of-hooks that are designed to enforce the invariants that really the programming language should enforce).
Edit: The other nice things about hooks is their composability (and this is in fact related to what I said above). With class components, a component can have one state object, so it's hard to compose with other "mixin" type behaviors that need their own dedicated state. You ended up with weird patterns like higher order components (à la Redux withStore) that have basically ceased to exist with hooks (replaced by a useStore hook which can opaquely manage its own state under the hood).
Sure. But search anything about React, and you'll see examples in hooks.
I don't even understand the reason why class-based is "legacy". Why are hooks inherently better? Code-reuse is a factoring concern, not a paradigm concern. And component-life-cycle bugs are now replaced with nearly impossible to understand callback stacktraces.
Can you give any example where hooks helped readability without trading it for extremely high complexity behind the scenes? I maintain a large React codebase part-time. The client is a very good friend of mine and I was the one who chose to make my own life miserable by selecting React. Needless to say I won't touch/introduce anything "new and/or popular" for customer projects with a ten-foot pole for the rest of my career.
I used both class-based (thank goodness?) and hooks based components but only coz React ecosystem forced me to, class-based were frozen and left in a sorry state - as if React's dictator-in-chief (forgot whoever they are/were, don't want to know - tried to engage once in writing the "beta" React docs but they were horribly toxic in response for no reason) is the only smart person(s) ever and all these OOP language designers are... No, dear Kim Jong(s), you were the ones abusing JS classes in strange counter productive ways and I easily found better OOP patterns for my class-based components. Then I met hooks - the definition of anti-productive. Not to say people don't have a right to write/reflect whatever madness in their code they want to but for me it's a tragedy their "work" became so popular. I don't mean to belittle people who actually have it but hooks is what comes to mind when I think of what PTSD must feel like. I no longer take up JS/TS SPA projects. For the mental strain - the pay feels peanuts compared to native mobile app development so why bother.
For example a flurry of setStates could be wrapped up in one single state. If it gets too complex - into a reducer.
Components that don’t benefit much from splitting up could have their business logic wrapped into a context, and let the view code be just jsx without all the interweaving of code and templates.
Maybe the one benefit of classes was like it forced you to think in business logic, then render. React still has that, you just need to dive a bit deeper into its toolbox.
The result usually turns out much more flexible - contexts neatly wrap business logic for all of its descendants, classes don’t.
I think this was maybe because react actually allows you to write messy code, and it’s still performant and works. But in the end it just kinda postpones the inevitable maintenance burden.
I guess solid.js from the looks of it might postpone it a bit more. I just worry that solid looks more like magic, and some invariant somewhere will just break and I wouldn’t know what sequence of reactions actually led to that infinite loop that crashed the page. Haven’t tried it myself though, might more understandable in the end…
reply