Как я могу эффективно перейти на значение внутри Reflex.Dynamic?
Допустим, у меня есть некоторое состояние приложения, поддерживаемое в некоторой бэкэнд-системе. Это выглядит так
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
Я почти уверен, что смогу выяснить, как упаковать это в Dynamic, многократно запрашивая серверную часть, так что у меня есть
dynMyState :: MonadWidget t m => Dynamic t MyState
Я хочу сделать это в HTML. Я хочу, чтобы каждая часть структуры данных отображалась в div. Тем не менее, вещи, которые не существуют, не должны отображаться вообще, поэтому, когда ms2_maybe_char
является Nothing
не должно быть никакого div для этого, и когда MyState
это State1
не должно быть никакого div для State2
,
пара примеров для наглядности:
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
API как строительный блок? Я полностью упускаю смысл Рефлекса, пытаясь построить из одного Dynamic
значение, и мне нужно переосмыслить свой подход?
В частности, самый первый камень преткновения заключается в том, что я не могу легко проверить Dynamic, чтобы узнать, содержит ли он State1 или State2. Я мог бы потенциально использовать dyn
или же widgetHold
здесь и fmap
функция над dynMyState
который может рассматривать состояние как простое значение и генерировать m ()
действие, которое привлекает все это. Но затем я теряю все возможности совместного использования - весь интерфейс пользователя будет перерисовываться с нуля при каждом изменении состояния.
Примечание: это более подробный вопрос для продолжения, как я могу перейти на значение внутри Reflex Dynamic?, Что отличается / яснее в этом вопросе, так это дополнительное желание не терять эффективные обновления всего, что находится в проверяемом значении. Спасибо всем, кто помог в этом вопросе!
1 ответ
Ответ зависит от того, каковы ваши цели и требования. Если вы хотите наилучшего возможного совместного использования 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
Если вы получите Призмы, то от этой неловкости можно избавиться.