Hacker News new | ask | show | jobs
by bob1029 2327 days ago
Global state in one happy place is basically what we've done with Blazor.

Instead of using cascading parameters and other ridiculously complex ways of passing state around, we inject stateful services as scoped dependencies per client request. These are effectively just POCO models with a functional interface for mutating state. Then, we take dependencies on these throughout the web application (I.e. within each component or page). An example of one of these used heavily throughout would be UserSessionService. Certain aspects of the application may have their own dedicated state machines like LoginService (which is utilized only during the login process). LoginService takes a CTOR dependency on UserSessionService and it all plays together really nicely via Microsoft's DI.

We've even wired events from server-side directly into these services so its not just for handling the client-specific interactions either. Integrating server-side events is trivial. It felt a little weird at first, but it seems we are moving in a much more sustainable direction now. I can actually test my UI state machines in complete isolation from an actual browser. Also, because they are simply .NET implementations, we can reuse these for other aspects of the application.

3 comments

This sounds very similar to what we've been doing with XState[1] and React.

We have a "service layer" for React made up of state-machine-based services (although reactive services based on RxJS observables works as well). We also created associated custom hooks that allow developers to easily "inject" a service into their React component (use use React's Context API for our "DI container"). From there they can read the service state, or send events to it to trigger behaviour that is encapsulated in the service itself.

We even have the same "most used" service; a UserSession service manages OAuth based login flow and session management.

The best part of this approach is that our service layer started in an Angular based proof-of-concept before we lifted-and-shifted it all into React.

[1] https://xstate.js.org/

How much does the react wrapper do? Ie how easy would it be to support Angular or Vue? I imagine just aligning syntactic conventions?
React wrapper doesn’t do much, and it is very easy to port to other UI frameworks.

Here’s a follow-up post with a gist of what the React integration looks like.

https://news.ycombinator.com/item?id=22294087

Holy, this is the first time I've heard of it, but it sounds really great.

> Instead of using cascading parameters and other ridiculously complex ways of passing state around

So much this! There are too many folks stuck in the 'container' component pattern when really you should never pass a prop that can be queried from state. Working like this results in a sustainable application that's flexible, like you _state_ xD

I'm going to give this a really close look, thank you.

We found similar frustrations with having state flow with the HTML structure. From a novice perspective I can see how that might seem desirable, especially considering how concise it looks for sample implementations when you are doing 2-way binding.

But, once you get into really complicated scenarios where structurally-unrelated components are statefully-related (e.g. navbar interacts with some component in an entirely unrelated modal), things get very nasty without some common arbiter of state being shared between these components. You can usually solve this in some way with all the SPA frameworks I've worked with, but Blazor is the first case where building these state machines as C# services has knock-on benefits that simply can't be ignored anymore IMO.

Overall, separation of state machines from the UI seems the be the theme, and certain technologies can do this a lot better than others.

Ok, so .NET just works on a Mac now, very cool. Feel like Microsoft is heading toward a glow-up moment in the near future. Keep up the good work.