How can I branch on the value inside a Reflex Dyna

2019-02-26 01:06发布

问题:

in the simplest case, say I have a Dynamic t Bool, and when the value is true, I want a single empty div to exist, and when the value is false, I don't want there to be any dom element.

slightly more generally, if I have a Dynamic t (Either MyA MyB), and I have functions that know how to render given a Dynamic t MyA or a Dynamic t MyB, how to I call the appropriate function to render?

回答1:

If you need to switch the widget you probably need one of:

dyn :: MonadWidget t m => Dynamic t (m a) -> m (Event t a) Source

or

widgetHold :: MonadWidget t m => m a -> Event t (m a) -> m (Dynamic t a)

Since you've mentioned you've got Dynamic at hand, we're gonna use dyn:

app = do
  switched <- button "Alternate!"
  flag <- foldDyn ($) False (not <$ switched) -- just to have some Dynamic t Bool
  let w = myWidget <$> flag
  void $ dyn w

myWidget :: MonadWidget t m => Bool -> m ()
myWidget False = blank
myWidget True = el "div" $ blank

The basic rule is that, due to the higer-order nature of Reflex, if you want to swap-out something, you need to have Event/Dynamic that yields a widget as a value. That's why dyn takes Dynamic t (m a) as its parameter (and appropriately, widgetHold takes Event t (m a). And that's why we've mapped over Dynamic t Bool to have a dynamic that has our widget building action as a value.

It's worth mentioning, that neither dynamic/widgetHold does virtual dom/diffing to speed the rendering. With reflex you can be more explicit about what updates what (a Dynamic/Event t Text can affect node text directly, without rerendering whole node) and you should take advantage of that. If not then large portions of page will be swapped and it can yield significant performance hit.