Home > Net >  Do I have to worry about a Dynamic firing even when the value does not change?
Do I have to worry about a Dynamic firing even when the value does not change?

Time:02-16

Using reflex-dom I found myself writing the following code:

dynShowNumbers <- holdDyn False $ catMaybes $ updated dynMaybeShowNumbers

where dynMaybeShowNumbers :: Dynamic t (Maybe Bool) fires, whenever a key is pressed or released, but it only has a value unequal to Nothing, when one of two specific keys change status (i.e. pressed or not-pressed). It fires Just False when one of the two keys is being released.

The reason is that I show a virtual keyboard that generally depends on any event of a key being pressed or released. For dynMaybeShowNumbers, I simply filter out two relevant keys that need to be hold down to show the virtual numpad.

I could easily write simpler code where dynShowNumbers :: Dynamic t Bool does not rely on the Dynamic t (Maybe Bool) as above.

However:

In that case, whenever any key is pressed I get my dynShowNumbers firing:

False---False---False------False--True---True----False----False----...

Whereas the above code would result in

False-----------------------------True-----------False-------------...

for the same input.

I feel, I need the above line to avoid dynamic re-rendering of my virtual keyboard--even when nothing changes.


But is the line above good practice? Is there an efficient function for this in the library (can't find it)? It's similar to the task of removing duplicates from a list.

CodePudding user response:

You have a few options! In Reflex.Dynamic, you can use these hold variants:

-- | Create a new 'Dynamic' that only signals changes if the values actually
-- changed.
holdUniqDyn :: (Reflex t, MonadHold t m, MonadFix m, Eq a) => Dynamic t a -> m (Dynamic t a)

-- | Create a new 'Dynamic' that changes only when the underlying 'Dynamic'
-- changes and the given function returns 'False' when given both the old and
-- the new values.
holdUniqDynBy :: (Reflex t, MonadHold t m, MonadFix m) => (a -> a -> Bool) -> Dynamic t a -> m (Dynamic t a)

There seems to be a more principled, type-based approach in Reflex.Dynamic.Uniq. That whole module is focused on such situations. Unfortunately, I don't see hold variants for it.

  • Related