假设我有一些在某个后端系统上维护的应用程序状态。它看起来像这样
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 }我还有一个从后端系统获取最新状态的函数
getLatestState :: IO MyState我非常确定我可以通过反复查询后端来弄清楚如何将其打包到动态中,这样我就有了
dynMyState :: MonadWidget t m => Dynamic t MyState我想将其呈现为html。我希望数据结构的每个部分都呈现到一个div中。然而,根本不应该呈现不存在的东西--因此,当ms2_maybe_char为Nothing时,不应该为其提供div,而当MyState为State1时,则不应该为State2提供div。
为了清楚起见,有几个例子:
State1 (MyState1 "foo" 3)变成了
<div class=MyState1>
<div>foo</div>
<div>3</div>
</div>和
State2 (MyState2 False Nothing)变成了
<div class=MyState2>
<div>False</div>
</div>理想情况下,只有在必要时才应该修改DOM的每个部分-因此,如果ms2_maybe_char从Nothing更改为Just 'a',则需要创建一个新的div。或者,如果ms1_text从"foo"更改为"bar",那么我们需要在DOM中更改该字符串。但是,更改ms1_text不应导致重绘同级节点或父节点。
我应该如何组织我的代码?考虑到getLatestState应用编程接口作为构建块,这有可能实现吗?我试图在单个Dynamic值的基础上构建Reflex,这是不是完全错过了Reflex的要点,我需要重新考虑我的方法?
特别是,第一个障碍是我不能轻松地检查动态以了解它是包含State1还是State2。我可能会在这里使用dyn或widgetHold,并在dynMyState上fmap一个函数,该函数可以将状态视为一个简单的值,并生成一个绘制整个内容的m ()操作。但是,我失去了所有的共享--每次状态改变时,整个UI都会从头开始重新绘制。
注意:这是How can I branch on the value inside a Reflex Dynamic?的一个更详细的后续问题。这个问题的不同之处/更清楚的是,它还希望不会丢失检查值中所有内容的有效更新。感谢在这个问题上提供帮助的每一个人!
发布于 2017-03-06 10:07:50
答案取决于你的目标和需求到底是什么。如果你想要最好的dom共享,从两个独立的函数renderState1和renderState2派生而来,我认为应该使用virtual-dom。
但实际上,这听起来像是您希望对添加到DOM的内容有一些精确的控制。
如果你手中有修改过的renderState1和renderState2版本,每个版本都有一个Maybe State1或Maybe State2参数,那么你可以做一件简单的事情,那就是构建一对这样的动态可能,并使用css属性隐藏其中之一:
let mState1 = (\c -> case c of
s@(State1 _ _) -> Just s
_ -> Nothing
) <$> dynMyState
mState2 = (\c -> case c of
s@(State2 _ _ _) -> Just s
_ -> Nothing
nothingHider a m =
let atr = bool mempty ("style" =: "displayNone") . isJust <$> a
in elDynAttr "div" atr (m a)
nothingHider mState1 renderMaybeState1
nothingHider mState2 renderMaybeState2如果你使用derive Prisms,那么很多尴尬都可以摆脱。
https://stackoverflow.com/questions/40497229
复制相似问题