Fork me on GitHub
#reagent
<
2022-01-07
>
lilactown17:01:29

what do people think about having the capability to create reactions with history? e.g.:

(def counter (r/atom 0))

;; a "reactive reduce"
(def counts (r/reduce conj [] counter))

(swap! counter inc) ; 1
(swap! counter inc) ; 2
(swap! counter inc) ; 3

@counts
;; => [0 1 2 3]

p-himik17:01:56

FWIW I can remember only two places where that might be useful - undo/redo mechanism in re-frame and a similar thing but in re-frame-10x. But implementing something like that using your mechanism would also require an ability to circumvent the mechanism - i.e. to rollback from 3 to 1 above, you want to both reset counter to 1 and to reset counts to [0 1].

lilactown18:01:09

yeah it's not really useful for undo/redo

lilactown19:01:11

i think it could be useful for relatively static higher order operations though, like filtering values

lilactown19:01:22

(def evens
  (r/reduce
    (fn [prev v]
      (if (even? v) v prev))
    0 counter))

lilactown19:01:26

normally you would have to maintain a list of all the counts in the source, filter the list then take the first. in this case the source can be a single value and we filter each individual value as it's propagated

p-himik19:01:43

How is what you propose different from just using add-watch and swapping an extra ratom in there?

lilactown19:01:58

you can add dependent reactions to it

lilactown20:01:24

(re-frame/reg-sub ::counter #(:counter db))

(defn only-evens
  [prev v]
  (if (even? v) v prev))

(def evens (r/reduce only-evens 0 (re-frame/subscribe ::counter))

(defn counter-view
  []
  [:div
   [:div "Count: " @(re-frame/subscribe ::counter)]
   [:div "Even count: " @evens]])

lilactown20:01:10

you could also cut off calculations using reduced for performance

p-himik21:01:06

Funny you should mention re-frame - in that setting, I would definitely try to avoid r/reduce. :) And if I think about it outside of those preferences, I'm still not entirely convinced such a [relatively] complicated thing justifies the value it brings. But maybe someone else might chime in and provide more useful commentary.

lilactown21:01:59

why would you avoid r/reduce in a re-frame context?

p-himik21:01:01

Because it's an implicitly derived state without any options on undo/redo.

p-himik21:01:09

If I needed some sort of a reduced accumulator, I'd definitely store both the accumulator and the last value fed into the reducing function in app-db itself.

lilactown03:01:59

the reason is because you want to have the ability to undo/redo?

p-himik07:01:17

Undo/redo, stable code reloading, saving and restoring state, central storage for monitoring - all the nice things that follow from the re-frame model.