Best Practices Around Global State in Halogen Apps

Apologies if this has been asked before. I’m wondering what the current best practices are for handling global application state in Halogen.

Real World Halogen seems to make use of the “higher-order” Connect component along with Buses. Is this still the ideal way of accessing/interacting with global state among different components (each of which might require interacting with different aspects of that global state)? Is there a simpler approach involving, perhaps, Hooks?

More generally, how should complex global state be modeled? Should it be self-contained within a single Model type (similar to what’s done in Elm), thus practically necessitating the use of lenses? Or are there other approaches which make more sense?

3 Likes

I cannot really answer your question, but am intrigued by the “buses” that real world halogen seem to use. Is there an explanation somewhere of how this works?

1 Like

I’m also interested in this, because I was just doing it this afternoon, thought “I wonder what the right way to do this is?”, Googled, saw your post, thought “Excellent! Someone’s asked already” then saw that the post was from only 3 days ago and there weren’t any answers yet…

I ended up doing an extremely low-rent thing, which was to write a capability to represent having global application-wide state, basically just duplicating MonadState but calling it GlobalState instead and using different method names, so that I could make my application monad an instance of GlobalState. Then I can access the global state from within components by saying gget, gmodify, etc., but can still access the local component state carried in the MonadState instance for HalogenM using get, modify, etc.

I have the feeling that there’s a better way to do this though. I’m using it for a global name supply shared across components, and it feels as though it ought to be doable with a hook. But I’ve only read about hooks so far and have never written one, so I don’t know!

Interesting approach; thanks for sharing. How do you handle the re-rendering of one component if another component gmodifies your GlobalState?

That’s where it ended up being “low-rent”, because it didn’t do any cross-component notification at all. (For a simple name supply, I figured it wouldn’t matter.) Also, it ended up being terrible, because I had to cut & paste all the instance definitions for StateT. And then I couldn’t even get it to work properly after all that. I then spent a very confused hour trying to figure out hooks. Finally I gave up and stuck a Ref Int in my read-only environment and switched to just having a ReaderT Env Aff monad stack. I consider that a total defeat. I’m still very interested in what the right way to do this might be!