5 ms·
What's the benefit of this over class syntax? If we had decorators in the language already we could make field reactive: class Component extends React.Comp
by spankalee 6y ago
What's the benefit of this over class syntax? If we had decorators in the language already we could make field reactive:
class Component extends React.Component {
@state show;
render() {
return
<div>
<button onClick={() => this.show = !this.show}>Show Menu</button>
// Mounted with show = true and unomunted with show = false
{this.show && <MenuDropdown />}
</div>
}
}
Hiding the underlying stateful objects that back React components seems like it causes more confusion and complicated APIs than it's worth. Likewise closures returning closures and state defined with function calls seems like re-inventing classes.
Just make the component itself stateful and the lifecycle explicit and it's all so much simpler. Then attack the problem of composing JS classes from pieces with tools available to all JS classes, not just the framework at hand.
- obedm 6y ago(author here) I don't have anything to add, you guys have great arguments, I just want to show appreciation for starting a good debate based on a code example I did :)
- nikki93 6y agoIt seems like the main benefit the authors of hooks get at is being able to encapsulate a library's logic into hooks that you can reuse, so eg. you could do `const [data, loading] = useQuery('some query');` and the query is aware of lifetime etc. without needing to use mixins or multiple inheritance or traits or something else like the component or ECS paradigms from game engines (that each have their pros and cons). You could have a stateful `this.query` object in your class, but you basically have to spread the code for that around (calling mount / unmount handlers or events) vs. just mentioning it in one place and having it be able to use more hooks internally etc. It's basically like an `import` statement for your component.
- spankalee 6y agoThis is my point about attacking composition with what we have for classes - because reuse and composition are problems not limited to UI widgets. Your query example is easily handled by a mixin: // Queryable provides this.data and this.loading and // hooks into the lifecycle class MyComponent extends Queryable(Component) { query = 'some query'; render() { // ... } } You can also use helper objects: class MyComponent extends Component { query = new Query(this, 'some query'); render() { // ... } connectedCallback() { this.query.connect(); } } I understand that you have to wire up the lifecycle methods this way, but it's at least low-magic and easily understandable. I don't mind it. And even though decorators aren't standard yet, they can be used for composition too. My point is that these problems aren't unique to React and deserve patters and solutions for all JavaScript programming. React is statefull and object-based under the hood, but just trying to hide it.
- gbear0 6y agoI agree with the grandparent that hooks are a weird hack and it drives me nuts every time I have to create one and can't use a closure to precompute some stuff and have better control of the lifecycle on functions/data outside the actual render function. So in the end of all this I've found I much prefer the class syntax cause it just makes more sense and does a much better job (for me) at declaring code patterns and shape than trying to follow code paths in/out of different effects (which oddly enough reminds me of the horror days of following code paths through multiple levels of inheritance). However, there is a major value hooks provide over class components and that's the composability of the lifecycle effects. The problem with class components is that code for a lifecycle is broken across multiple functions and interweaved with other effects. This happens because the declarative model of the component tree clashes with the imperative ordering we code up for lifecycle functions attached 'within' each class component. The fix is to turn lifecycle effects into first level declarative concepts themselves (like in hooks) so they're not 'within' the component, instead they're more of a has-a relationship. This would actually be rather simple to do, drop the lifecycle methods in a component, and add a new Component.addEffect function (or, cause I'm a big fan of decorators, you could have some decorator to declare what effects should be used). And each effect would be another class that inherits from Effect. I think the hardest part to think about is how you interweave the effects like people do in hooks as one output becomes the input for another, but I think this is probably the wrong way to think about it. Instead if you think of it as an Effect tree then each Effect is just a 'render' function where you're passing in other effects as the props and the output is passed down the tree, so you'd just need an inline effect function that would compose 2 effects together the same way we do with components. At this point the conceptual model is extremely easy cause it's declarative trees all the way down! RootComponent |- ComponentA |- effects ||- lambda effect -- myClickEffect || |- myStateEffect ||- lambda effect -- myKeyEffect || |- myStateEffect ||- myCleanupEffect |- children |- ComponentB |- effects |- children |- ComponentC |- effects |- children ... Anyone wanna pass this idea onto the react team that'd be awesome cause I'd love to see this added for Class components to make them more composable as well as having better sharing of ideas between hooks and class components :)