Hacker News new | ask | show | jobs
by kecupochren 1701 days ago
I find the state of things in React, pun intended, a bit sad. Hooks are definitely an improvement over class based components but it still suffers from the same issue - having logic and state in the view layer leads to spaghetti code. Not to mention dependency arrays which are easy to get wrong and the weird syntax you end up with everywhere.

I'm a big fan of MobX and it pains me to no end that it didn't took off better. It's a godsend from like 5 years ago and it makes so many of these React pain points disappear.

Instead of adding state to your components here and there, it works outside of the view layer. You define the model, derived computed views, actions and then just use it inside your components. You never ever worry about performance because MobX knows what is used where and it will optimize your renders automatically.

Moreover, dealing with state outside of the view layer makes it much more easier to refactor, reason about and test your app. Sure, you can do the same with Redux but it's 10x more code.

I recommend this article on this topic by the author - https://michel.codes/blogs/ui-as-an-afterthought

2 comments

I +1 MobX wherever I see it mentioned, but I have to disagree here:

> having logic and state in the view layer leads to spaghetti code

Sometimes it makes sense to put logic and state in your view components, and the wonderful thing about MobX is that it doesn't care. It lets you freely move your state around to wherever you want it to live: inside components, outside components, in a module-scoped object, in a global store, all of the above. It's just JavaScript objects.

For those fighting with hooks: one of the best things about MobX is that it does all dependency-tracking (for effects, but also for components) automatically and flawlessly. An entire problem-space that's usually easy to mess up just vanishes in front of your eyes. Going back to anything else feels like going back to the dark ages.

I'm not familiar with MobX, but I am a big fan of Jotai (https://jotai.pmnd.rs/). It is a spiritual offshoot of Facebook's experimental(?) Recoil library.

It is a bottom up approach to state. Everything is modeled as atoms. Atoms can be defined in any module and are accessed by simply exporting/importing from/to the module. Simply call the useAtom hook and you're now using that state atom.

Under the covers it is scoped via a top-level React context, I believe.

Atom derivation, read/write, async, it's all there. It also hooks into a lot of other popular state libs like redux, XState, Zustand and many others.

I much prefer it to Redux because there is zero boilerplate and extremely flexible. It can be easy to hang yourself with all the extra rope it gives you if you aren't careful though.

> Sometimes it makes sense to put logic and state in your view components

Of course, I do that a lot with generic, reusable components. Once I know it's too complex I extract it to model that gets passed through props. Win/win

This 100%. I still don't understand why React devs are so infatuated with colocating business logic with the UI that presents the result of that business logic. Sure, in the small (a todo list app? a weekend project?) it's probably a lot easier to reason about if you just jam everything into the same file. But why is it so difficult for people to see that the reason their large application is bloated, untestable, unmaintainable, etc is directly due to the blatant violation of separation of concerns that they're parroting?

I feel like part of this is due to some devil's bargain on the part of the React maintainers. They want mindshare, and they know that it's easier to gain mindshare if the behaviour of the app appears simpler, and that appearance of simpler is easier to achieve if the behaviour is relegated to a smaller number of files...

but hooks allow you to easily move business logic outside of your component. most business logic is simple so people use it inline. isolating it makes it pretty easy to test and reuse
That's true. But to echo the underlying theme of the original blog post, it is difficult to ensure that a large team of developers (of varying skill levels) maintains a consistent approach to this. Different developers likely have different opinions of where that "simple" threshold is that warrants factoring out the business logic. And, when the push of a deadline comes to shove, it is tempting to just throw all the shit in the component with the promise that we'll refactor it at a later date.

More fundamentally, I feel like putting business logic hooks in a component (even simple ones) sacrifices the cleanliness of components as simple stream transformers: input some scalar props, output some HTML. As soon as you start calling hooks within a function component, it's no longer purely functional. You have side effects. And those side effects result in a component that's trickier to debug and trickier to test.