Hacker News new | ask | show | jobs
by colejohnson66 1551 days ago
> ...or go back to class based components?

Was there anything wrong with class components? It's what I learned half a decade ago, and the idea of a "state" object made so much sense. Now, with hooks and whatnot, it seems like React is trying to be "functional" without actually being so.

5 comments

I’ll prefix by saying I agree with a lot of the criticisms, and I’ve experienced first hand how hard to explain and error prone hooks are. But for this post, let me defend the concept.

The idea, in a very rough nutshell, is to allow separating behavior and presentation.

Hooks are the reusable unit of behavior. You compose hooks into more complex hooks that might implement loading and saving data from/to the server, for example.

Then you can use this hook with different components, or use the same component in a different context with a different data source. This can be very powerful if used well.

But as I said at the beginning, hooks are unfortunately also very difficult to get right.

To expand on this, many of the things that hooks now make easy were bespoke per-class implementations with details that leaked into every lifecycle hook. Think of how you’d write a chain of useMemo calls in a class component to see just how bad it was.
Why would you need useMemo in a class component? You can just attach a memoized instance of the function to the component
State wasn't evil, the lifecycle callbacks were. I don't think they ever deprecated setState, but I'm pretty sure they've nudged people away from the lifecycles..

Class components when needing more complex behaviours related to lifecycles/context had the choice of:

a. Hard wiring up all the different lifecycle events to bespoke systems, on a per component basis (use same thing in 5 places? Implement it 5 times)

b. export const ActualWorkingComponent = HOC(HOC(HOC(HOC(NonWorkingWithoutHocComponent,{conf4}),{conf1}),{conf2}),{conf3});

I will fully admit that useState is more aimed at singular/simple values, so a more complex object is a pain to directly copy over. (useReducer or wrapping setState could work, as the child components shouldn't re-render unless their props change).

But it is so much nicer to have the dependencies at the start of the the functional component, and not in a horrid callstack at the bottom, with 3 different ways of defining which prop gets which HOC's values/functions and then injecting even more callbacks to munge those values from the out HOCs to use in that HOC to make it's output good for next HOC...

Instead, it's just:

    const {widgetId} = useRouterParams();
    const widgetData = useSelector(selectWidgetById(widgetId));
No mess, no fuss, use it it in a few places? Wrap it up in a function of it's own.
With class components, lifecycle management is trickier to encapsulate and reuse since you have to split such things up and scatter them across several different methods or wrap the whole component in a HOC, and in general class components require more boilerplate. Thus you'll usually end up with code that's just a bit more spaghetty than with function components. With hooks, you can at least encapsulate some specific behavior behind exactly one function call without jumping through any extra hoops.
I also liked/like the idea of one state object. With hooks now they really discourage packing everything into one state object and you either have to use a bunch of different `useState` statements for your different variables or pack a big state object in one `useState` but then you face big performance issues with needless re-renders when you only change one element of the state object.
Take a look at useReducer(no 3rd package, part of the React api)
I would say mixing state and behaviour was the main problem with class components (and oop), although it might be a better problem to have than all the approaches supported simultaneously (some code with class components, some hook heavy, etc)