Let's say I have some application state, maintained on some backend system. It looks like this
data MyState = State1 MyState1 | State2 MyState2
data MyState1 = MyState1 { ms1_text :: Text, ms1_int :: Int }
data MyState2 = MyState2 { ms2_bool :: Bool, ms2_maybe_char :: Maybe Char }
I also have a function to get the latest state from the backend system
getLatestState :: IO MyState
I'm pretty sure I can figure out how to package that up into a Dynamic by repeatedly querying the backend, so that I have
dynMyState :: MonadWidget t m => Dynamic t MyState
I want to render this to html. I want each part of the datastructure to render to a div. However, things that don't exist shouldn't be rendered at all - so, when ms2_maybe_char
is Nothing
, there should be no div for it, and when MyState
is a State1
, there should be no div for the State2
.
a couple examples for clarity:
State1 (MyState1 "foo" 3)
becomes
<div class=MyState1>
<div>foo</div>
<div>3</div>
</div>
and
State2 (MyState2 False Nothing)
becomes
<div class=MyState2>
<div>False</div>
</div>
Ideally, each part of the DOM should only be modified if necessary - so if ms2_maybe_char
changes from Nothing
to Just 'a'
, then a new div needs to be created. Or if ms1_text
changes from "foo"
to "bar"
, then we need to change that string in the DOM. However, changing ms1_text
should never cause the sibling or parent nodes to be redrawn.
How should I structure my code? Is this even possible, given the getLatestState
api as a building block? Am I entirely missing the point of Reflex by trying to build off of a single Dynamic
value, and I need to rethink my approach?
In particular, the very first stumbling block is that I can't easily inspect the Dynamic to know if it contains a State1 or a State2. I could potentially use dyn
or widgetHold
here, and fmap
a function over dynMyState
which can treat the state as a simple value and generate a m ()
action that draws the whole thing. But, then I lose all sharing - the entire UI will be redrawn from scratch on every single state change.
Note: this is a more detailed followup question to How can I branch on the value inside a Reflex Dynamic?. What's different/clearer about this question is the additional desire to not lose efficient updates of everything inside the inspected value. Thanks to everyone who helped on that question as well!