Hacker News new | ask | show | jobs
by com2kid 629 days ago
The complaint is they prior to hooks react didn't have any of this complexity. It was pretty simple to understand. Class components works mostly as you expected them to. There are a handful of things that were really hard to do with class components that hooks + function components made easier, but lots of other things became more complicated with each new set of features react has added since then. At this point the solution to "class components are complicate" is far more complicated than class components ever were.
1 comments

I understand the complaint but my point is that, in my experience (which admittedly might be biased), the complaint usually does not resonate with anyone that did actually use React for at least a moderately complex app.

Hook's API is not perfect but it's a good-enough abstraction that allows the user to have even better abstractions and separation of concerns.

Actual React users did not care about that because the pragmatism far outweighs the theoretical ugliness... which honestly is not even that ugly if you have a mental model similar to coroutines (of course if all you do is OOP a class will look better to you...)

I have recently been fixing some stuff in my old React pre-hooks code and I hated it because class-based components had all sorts of concerns intermixed on their lifecycle methods... no matter how much you tried to abstract them.

Abstracting those into reusable hooks was a breeze and made everything much easier to follow and maintain.

Hooks are far better from a pragmatic point of view.

> There are a handful of things that were really hard to do with class components that hooks + function components made easier, but lots of other things became more complicated

Like what? Does not match my experience at all.

> I have recently been fixing some stuff in my old React pre-hooks code and I hated it because class-based components had all sorts of concerns intermixed on their lifecycle methods... no matter how much you tried to abstract them.

The lifecycle concerns are still there, sometimes things need to happen when a component is first displayed, and sometimes things need to happen with a component is removed from the page. It is just handled differently now.

My other issue with hooks vs classes is that, and I say this as someone who loves FP, the best application of OO programming is for UIs. At the base level, a text input field has an object created in the browser, and that input field has state. UIs are inherently stateful things. The OO model is natural for building UIs, you typically shove an object on the screen, that object has some state, and the user manipulates that state.

OO is a great abstraction for UIs. IMHO it is a pretty bad abstraction for most other problem domains, but for stateful UIs, OO maps pretty darn well to what is actually happening!

I just don't see the benefit of throwing another abstraction layer on top of all that.

One reason I love Svelte 4 (haven't tried 5 yet) is that it is so bloody simple compared to React. After years of programming in React, I was literally 5x more productive in my first ever Svelte project than I had ever been in React.

All I need is a good way to encapsulate HTML components for reuse (which is fundamentally an OO thing, instantiate new instances of a component template!) and a good state management system that pushes state changes out to subscribed components.

For me, it's not OOP vs functional. I find "functional" to be a misnomer as its applied to most react components. Functional used to have a clear definition about having a stable return value and only varying based on parameters.

However, the same problem started afflicting class-based components prior to the introduction of hooks. When fibers were created, component instances no longer tracked their own state. State was injected into them prior to invoking the render function, based on reconciliation. I suppose even before that the reconciler was still choosing which component instance to render.

But at least components had an identity that could be addressed in application code. Now component identity is effectively the fiber instance identity (or its alternate), which is impossible to get a reference to.

In real life, people really seem to like hooks. I can see some of the benefits they provide over the OOP class-based component model. But I can't avoid also seeing the mental foot-guns associated with it.

The very first time I every tried to write a react app, I got tripped up by this. I add a component that moves around in a parent component conditionally. So I had `const inner = <Inner />`, and then based on some condition it would be inserted in various places in the rendered parent component.

Of course after much wailing and gnashing of teeth, I learned that this variable declaration wasn't establishing a component identity. It merely creates an "element", even if it has a key attribute. Component identity, as used to retrieve state, is fundamentally tangled up with reconciliation which can only see the final rendered output of a component. No other components can have state, at least as recorded by a hook.

Most people don't seem to have trouble with this, but it's not how I naturally think of things.

Unless my memory is very hazy none of that is related to hooks.

Identity in React has always relied on vDOM structure or `key` which was introduced in React 0.4.0 (July 17 2013, <2 months after initial public release).

> For me, it's not OOP vs functional.

Neither is for me. Note I didn't mention functional once.

> Identity in React has always relied on vDOM structure or `key` which was introduced in React 0.4.0

You are correct. But so, I believe, was I. Apologies for being unclear. vDOM structure is determined based on the return values from render functions. As opposed to the line of code where elements are created. So if you have `const cmp = <Comp />` in a render function, it doesn't have an identity yet. As you note, that will be determined later, sometime after this render function returns. It might not have a state at all. It might even have multiple states. If the current rendering is an update, `cmp` might be a mount instead.

All these determinations are made based on the content (structure and key attributes) of the assembled vDOM and the reconciliation heuristics.

> Note I didn't mention functional once.

I assumed that's the comparison you were drawing with this line. "better" than what?

> of course if all you do is OOP a class will look better to you

> of course if all you do is OOP a class will look better to you...

Funny thing is, I do not know what coroutines are and have zero experience with them. I am object oriented class programmer who never cared about functional programming.

I figured hooks intuitively and straightforwardly when I had to work with react a year ago. Ok, function with state, but it was easy to read them, imagine what they do and maintain the code. It just seemed as an improvement over the old react to me, despite having no coroutines knowledge.

Exactly!

To be honest they're not full-blown coroutines (since the React runtime cannot control when the component progresses) which might be a bit more complex to grasp... but the idea of "yielding control" to someone else (i.e. to React, when calling one of its hooks) is there and as you say it's pretty straightforward.

> because class-based components had all sorts of concerns intermixed on their lifecycle methods

I think this just means your components are too large and try to do too many things. When your components are simple, their concerns are simple enough that they can immediately be understood, even if spread over several lifecycle methods.