> 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.
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.
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
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...
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.
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