[英]How can I efficiently branch on the value inside a Reflex.Dynamic?
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 我很确定我可以通过反复查询后端来弄清楚如何将其打包成Dynamic,这样我就拥有了
dynMyState :: MonadWidget t m => Dynamic t MyState
I want to render this to html. 我想将此渲染为html。 I want each part of the datastructure to render to a div.
我希望数据结构的每个部分都呈现为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
. 但是,根本不应该呈现不存在的东西 - 因此,当
ms2_maybe_char
为Nothing
,它应该没有div,而当MyState
是State1
, State2
应该没有div。
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. 理想情况下,只有在必要时才应修改DOM的每个部分 - 因此,如果
ms2_maybe_char
从Nothing
更改为ms2_maybe_char
Just 'a'
,则需要创建新的div。 Or if ms1_text
changes from "foo"
to "bar"
, then we need to change that string in the DOM. 或者如果
ms1_text
从"foo"
变为"bar"
,那么我们需要在DOM中更改该字符串。 However, changing ms1_text
should never cause the sibling or parent nodes to be redrawn. 但是,更改
ms1_text
不应该导致重绘兄弟节点或父节点。
How should I structure my code? 我应该如何构建我的代码? Is this even possible, given the
getLatestState
api as a building block? 考虑到
getLatestState
api作为构建块,这是否可行? 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? 通过尝试构建单个
Dynamic
值,我完全忽略了Reflex的观点,我需要重新思考一下我的方法吗?
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. 特别是,第一个绊脚石是我无法轻易检查Dynamic以了解它是否包含State1或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. 我可能会使用
dyn
或widgetHold
这里,和fmap
在功能dynMyState
它可以把国家作为一个简单的值,并生成一个m ()
吸引了整个事情的行动。 But, then I lose all sharing - the entire UI will be redrawn from scratch on every single state change. 但是,然后我失去了所有共享 - 整个UI将在每次状态更改时从头开始重绘。
Note: this is a more detailed followup question to How can I branch on the value inside a Reflex Dynamic? 注意:这是一个更详细的后续问题如何分支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!
感谢所有帮助解决这个问题的人!
The answer depends on exactly what your goals and requirements are. 答案取决于您的目标和要求。 If you want the best possible dom sharing, derived from two separate functions
renderState1
and renderState2
, I think that calls for virtual-dom
. 如果你想要最好的dom共享,从两个独立的函数
renderState1
和renderState2
派生,我认为调用了virtual-dom
。
But it actually sounds like you want to have some precise control over what gets added to the DOM when. 但实际上,您似乎希望对何时添加到DOM中的内容进行精确控制。
Something simple you can do, if you have modified versions of renderState1
and renderState2
in hand that each take a Maybe State1
or Maybe State2
argument is to build a pair of these dynamic maybes and use css attributes to hide one or the other: 你可以做一些简单的事情,如果你已经修改了
renderState1
和renderState2
版本,每个采用Maybe State1
或Maybe State2
参数是构建一对这些动态maybes并使用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
If you derive Prisms then a lot of the awkwardness can be gotten rid of. 如果你衍生出棱镜那么可以摆脱很多尴尬。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.