9 ms·
Why are so many comments about class components, I thought we ended that debate 3 years ago? Hooks are better because they allow you to reuse component logic,
by codeptualize 4y ago
Why are so many comments about class components, I thought we ended that debate 3 years ago?
Hooks are better because they allow you to reuse component logic, impossible with class components. They solve all the issues and gotcha's of HOC's.
Don't compare class components with hooks, compare HOC's with hooks.
The best way to grow appreciation for hooks is to try wrapping many HOC's and deal with conflicting props and "innerRefs". People seem to very easily forget the horrors of the old.
Also lets be real, hooks aren't that bad. Yes dependencies arrays and useEffect take some getting used to, but I rarely get into situations where I actually get into questionable territory. Use react-query/swr for fetching, use Zustand (or whatever) for state, and you cut out 95% of the problems.
Anyway, the new docs are great, well done, nice work!
- robertoandred 4y ago[flagged]
- spankalee 4y agoHooks are much worse because they poorly emulate classes. What you need for components is a stateful container, with an initialization phase, a render function that can be called for each update, and lifecycle methods that are called at lifecycle events. Classes give you exactly this: - Constructor for initialization - Class fields for state - A method for rendering that can be called multiple times, which can reference state - Lifecycle methods Classes are simple, standard, and give you everything you need for UI components. They were practically invented alongside the concept of UI components. Hooks try to cram all of this into the repeatedly called render method and it's just a failure. - You have to put initialization into callbacks because the whole component is called multiple times - It's difficult to manage object and callback identity across renders requiring useCallback() and useState() to fix - Lifecycle callbacks are put into hook arguments, but they're just trying to be methods and end up recreating the lifecycle closure every render. - Hooks have restrictive rules on their usage - Hooks make a function no longer just a function. It needs to be invoked inside a hook context, making it much less portable than a constructor - Hooks hide their state within the hooks system, making them much harder to introspect and debug. Hooks supposedly solve this composition problem and allow reusing logic, but that is entirely possible with classes. It's just a huge amount of FUD and misinformation to say that you can't do composition with objects. All you need is an object interface that is similar to the component interface that the component delegates to from its lifecycle methods. This is a simple and standard pattern to use and implement: it's just a single line of code per lifecycle method. And it's easily introspectable with a debugger: just follow object references to the helper objects. lit.dev does with with reactive controllers: https://lit.dev/docs/composition/controllers/ https://lit.dev/docs/composition/controllers/ It's a very simple alternative to custom hooks, and eliminates the need for all the builtin hooks.
- lmm 4y agoClasses with state are a nightmare. You can never tell what has changed or where. Having the state in the hook system where it's visible to your tools and you can actually see what's changed between one render and the next is a huge win.
- gnaritas99 4y ago[dead]
- spankalee 4y agoYou can do that with classes too though. We use decorators to make class fields reactive and track what changed between renders.
- dylanowen 4y ago100% this. Reading complex functional components is challenging because you're creating the functionality of a class with non of the organization.
- codeptualize 4y agoHow do you mean? Imo it's easier to organize as you can split up your logic into normal functions and custom hooks (which are also just functions). I also find functions much easier to read as there is no "this" and you can simply read them top to bottom for order of execution.
- dylanowen 4y agoSo I spent some more time reading through using HOCs in React and I think I'll have to give functional components more of a try. The specific example I was thinking of is https://github.com/graphql/graphiql/blob/50674292c55eadf0e61993ffbbc7a6983c608bf4/packages/graphiql-react/src/editor/response-editor.tsx#L37 https://github.com/graphql/graphiql/blob/50674292c55eadf0e61... but this component will probably always be complex because of the Codemirror interaction.
- recursive 4y ago> Hooks are better because they allow you to reuse component logic, impossible with class components I've heard this said before, but I don't understand. Could you give an example of component logic that can't be reused under class components?
- codeptualize 4y agoSure! It's generally about "stateful logic". Basically logic that relies on state and/or the lifecycle methods (componentDidMount, componentDidUpdate, etc) as with classes those are only available as part of a component. You can "sort of" reuse component logic with classes, the most common way is by using Higher order components (see https://legacy.reactjs.org/docs/higher-order- https://legacy.reactjs.org/docs/higher-order- components.html). The example in that article is pretty good: Subscribing to some external data source. That requires on mount, state, and on unmount. Using HOC's is not actually reusing logic though, it's creating more components and wrapping them to compose the logic. It's a workaround. HOC's have a bunch of downsides, imo the most obvious one is the props; you need to pass the previous props, and merge in the new ones. That can create conflicts. Another typical one is refs. You need to be very meticulous about structure and how you compose and order your HOC's to make sure it all works. In hooks you can define this stateful logic truly disconnected from a component, resolving a lot of the issues of HOC's as you can just call a bunch of functions without impacting the render tree. The "plumbing" is much simpler. Hope that is sort of clear, but let me know if I should clarify any of this.
- recursive 4y agoI appreciate the effort, but it's a bit over my head with respect to react stuff. For instance, I'm not sure what's meant by needing to merge props. I was under the impression that you could pass a subset of properties as an argument to setState, and all else would remain untouched. I wasn't thinking of using HOC's. I've done a bit of react, but never touched them. I'm just thinking of reusing logic using the same techniques I use to reuse logic in code. React famously asserts "it's just javascript". Javascript provides a way of reusing logic, namely functions. If I have two class components that have the same logic in them, I'm imagining just putting that code in a function. This is not a sophisticated argument. There might be some reason that wouldn't work, but I don't know what it is.
- spion 4y ago> impossible with class components I'm not sure thats really true. In a different world, the react constructor functions would have access to `this.useState` and `this.useEffect` and then you could extract any logic you like by dispatching `yourFunction(this)`. HOC are not the only alternative design. Hooks really push at the boundary of the language and I'm not sure they're an optimal path once you actually start dealing with state.
- codeptualize 4y agoAccess to this.setState would be horrible, imagine the conflicts. You need separate state, and then you sort of have hooks again.
- spion 4y agosee https://news.ycombinator.com/item?id=35192312 https://news.ycombinator.com/item?id=35192312
- rimunroe 4y ago> Hooks really push at the boundary of the language and I'm not sure they're an optimal path once you actually start dealing with state. How do they push at the boundary? I feel like so many people talk about them being magical, but I don't see how they're any different than any other effectful function call. Is the idea of tracking call order that exotic? This is a very simplified example of how hooks work under the hood: let hookStates = []; let currentHookId = 0; let firstRun = true; function endRun() { firstRun = false; currentHookId = 0; } function useState(initialValue) { const hookId = currentHookId++; if (firstRun) { hookStates[hookId] = initialValue; } function setter(nextState) { hookStates[hookId] = nextState; } return [hookStates[hookId], setter] } let actions; function run() { const [a, setA] = useState(1); const [b, setB] = useState(2); // this is done because we're not setting up event handling // and we need some way to trigger external updates actions = {setA, setB} endRun(); return a + b; } function assert(received, expected) { if (received !== expected) { let error = new Error(`Expected ${expected}, but received ${received}`); error.name = 'AssertionError' throw error; } } assert(run(), 3); actions.setA(3); assert(run(), 5); actions.setB(5); assert(run(), 8); actions.setA(1) actions.setB(-1) assert(run(), 0); Obviously this example doesn't include tracking more than one component, but as far as I know hook state gets tracked pretty much the same as the state on class component instances. I could understand thinking they're magical if you were under the impression you were the one calling the component functions rather than React, but I think my impression was always that it was still React's job to call the function component (otherwise, createElement seems like a waste). They might have at one point said that it was okay to do that in tests, but I'm not sure about that, and it would have been out the door the moment function components started supporting refs.
- gnaritas99 4y ago[dead]
- pharmakom 4y agoI guess it’s because whilst hooks improve on some aspects, they are quite counter intuitive and very easy to use incorrectly. I don’t think hooks is the final answer to side effects and state in react.
- hbrn 4y agoI remember a while ago, if you were to mention HOC wrapper hell in React community, most folks would jump to defend it. Eventually, React team accepted that it is a problem, and presented hooks as a solution. The very same people who would defend wrapper hell yesterday, would start crapping on it today. I think you're right that hooks are flawed and not the final answer, but the community won't accept it until "React gods" say so. It would be quite funny if React team eventually decides to go compiler way (a la Svelte) and all the people grasping for reasons to hate Svelte would have to change their opinions again.
- cercatrova 4y agoReact is already looking to use a compiler, but for memoization rather than fully removing the VDOM.
- pharmakom 4y agoTotally agree. The ultimate solution (imo) will come from the functional programming world and it will be a component monad, just it won’t look like that to the end user. It will probably leverage function-star in JS. It will enable unit testing of all component interactions and everyone will say it’s the best thing since sliced bread. Clojure devs will look on wondering why it took so long. Just my hunch!