State management


#1

I’ve been doing a lot of javascript recently and they have some really nice libraries for reactive state management of complex apps.
Some examples are redux and mobx.
Mobx I especially like. Behind the scenes it builds up a graph of what is dependent on what, so that if you change an ‘observed’ variable the changes synchronously propagate throughout the app. It also allows for easy ‘computed’ properties that are memoized and only recompute if the inputs change. It makes for fast, simple UI updates and avoids having a mess of listeners around.

What about some official Juce state management system? I think most of the parts are already there with Value, var and ValueTrees.


#2

Ive also been using both Redux and more recently switched to MobX in the React Native part of the app I’m currently working on. Definitely prefer MobX, at least for simple stuff - Redux was way too much wiring for basic CRUD type operations.

I’ve also thought about how this kind of thing could be implemented in JUCE - I already use a SharedResourcePointer to an object holding part of my app’s state so it can be accessed from different Components. I’m not sure how best to implement something like this in JUCE as I don’t fully understand the inner workings of MobX yet.

It seems that global state, which is what these libraries are providing, is generally seen as bad practice in C++. Having used them (in conjunction with React) it simplifies the thought processes massively. Just include the relevant Store in your component and boom, there’s your data. Use that data in your render method and it will re-render the relevant parts anytime that data changes.


#3

That’s generally how I tend to structure apps nowadays, usually around ValueTrees.

E.g. in Tracktion, an edit is just one big ValueTree, and everything else (GUI, playback, etc) is driven by classes that react to changes in the tree.


#4

Yeah I’d read that you do that. Similar to redux in some ways, having a single, big store and managing everything from there. What redux does is make it more formalised. But like adamski, prefer mobx for smaller projects.

It revolves around ‘observable’ variables. You mark a variable as observable (could be an array or map) and mobx will begin tracking usages of it globally, and builds up a graph of what relies on what, sending triggers down the tree if something changes.

Another key method is autorun. Code within an autorun will be called anytime that an observed variable that it uses changes. In a Juce context, you would wrap this around a Components paint function, so that for example if it’s using an observed variable ‘text’, it will automatically repaint when ‘text’ changes. I guess it’s similar to listening to changes on a ValueTree, but when it becomes much more useful is when the chain of reactions is longer than one. Like, when text changes, you need to go to a server to search, return those results to 3 places, transform it and update 5 things in the UI.

Another usage of autorun could be debounced autosaving.

To do this in Juce we would need a TrackingHandler class to manage building the dependency graph and tracking changes, and some additions to Value to tie it to the TrackingHandler. Then methods on the trackingHandler for doing autorun.

There’s other things too, like transactions that wait for a block of code to complete before computing all reactions at once.

Maybe a more advanced state management system in Juce isn’t so necessary, everyone likes to do it their own way. I guess mostly this me a bit miffed at my own badly written code that relies too much on ValueListeners and then having to deal with the resulting async screw-ups. These are just ideas from the web world. I think they definitely do some things right.