Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reflex.Collection.listWithKey samples Dynamic values too late #451

Open
bidigo opened this issue Mar 1, 2021 · 0 comments
Open

Reflex.Collection.listWithKey samples Dynamic values too late #451

bidigo opened this issue Mar 1, 2021 · 0 comments

Comments

@bidigo
Copy link

bidigo commented Mar 1, 2021

We have an issue in our app where we get annoying flicker in the UI whenever we use list or simpleList from Reflex.Collection. We're using reflex 0.8.0.0 and building with the latest obelisk.

We traced the culprit to the usage of Map.empty in listWithKey:

listWithKey
:: forall t k v m a
. (Ord k, Adjustable t m, PostBuild t m, MonadFix m, MonadHold t m)
=> Dynamic t (Map k v)
-> (k -> Dynamic t v -> m a)
-> m (Dynamic t (Map k a))
listWithKey vals mkChild = do
postBuild <- getPostBuild
let childValChangedSelector = fanMap $ updated vals
-- We keep track of changes to children values in the mkChild
-- function we pass to listHoldWithKey The other changes we need
-- to keep track of are child insertions and
-- deletions. diffOnlyKeyChanges keeps track of insertions and
-- deletions but ignores value changes, since they're already
-- accounted for.
diffOnlyKeyChanges olds news =
flip Map.mapMaybe (align olds news) $ \case
This _ -> Just Nothing
These _ _ -> Nothing
That new -> Just $ Just new
rec sentVals :: Dynamic t (Map k v) <- foldDyn applyMap Map.empty changeVals
let changeVals :: Event t (Map k (Maybe v))
changeVals =
attachWith diffOnlyKeyChanges (current sentVals) $ leftmost
[ updated vals
-- TODO: This should probably be added to the
-- attachWith, not to the updated; if we were using
-- diffMap instead of diffMapNoEq, I think it might not
-- work
, tag (current vals) postBuild
]
listHoldWithKey Map.empty changeVals $ \k v ->
mkChild k =<< holdDyn v (select childValChangedSelector $ Const2 k)

Basically, what seems to happen is that the value of the Dynamic vals map argument is only used at the PostBuild time instead of being sampled and used in the call to the listHoldWithKey. In our example this leads to a list widget in our UI to initially get rendered as an empty list and then at the next frame to get filled with data, which scrolls all the other widgets that come after it.

We can confirm the problem goes away when using the sampled value of vals when calling listHoldWithKey.

Is this usage of Map.empty intentional, perhaps because of performance reasons? If not I could go ahead and prepare a patch for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant