This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-26
Channels
- # announcements (17)
- # babashka (68)
- # beginners (8)
- # biff (14)
- # calva (25)
- # cherry (10)
- # clj-kondo (1)
- # clj-on-windows (12)
- # cljsrn (6)
- # clojure (134)
- # clojure-berlin (1)
- # clojure-europe (33)
- # clojure-nl (4)
- # clojure-norway (6)
- # clojure-uk (10)
- # clojurescript (9)
- # datalevin (8)
- # datomic (34)
- # docker (1)
- # emacs (31)
- # fulcro (6)
- # honeysql (8)
- # java (7)
- # joyride (14)
- # kaocha (7)
- # malli (11)
- # nbb (4)
- # off-topic (11)
- # pedestal (14)
- # rdf (53)
- # re-frame (6)
- # reagent (39)
- # reitit (2)
- # releases (9)
- # rewrite-clj (14)
- # shadow-cljs (97)
- # specter (1)
- # testing (5)
- # tools-deps (12)
- # vim (4)
- # xtdb (9)
Is there a way to watch a path in the app-db and when it changes dispatch an event with the new value? (e.g. to save it to localStorage
)
You can use the built into re-frame on-changes
interceptor factory function to create an interceptor that you can then register as a global one. Or you can write your own global interceptor if that makes more sense.
Ah okay. So in my case I should write an interceptor that appends the local storage event to the effects map under :dispatch
?
Looking at on-changes
it should probably work like this?
(defn save-path-to-local-storage
[path]
(rf/->interceptor
:id :save-path-to-local-storage
:after (fn [context]
(let [new-db (rf/get-effect context :db)
old-db (rf/get-coeffect context :db)
new-in (get-in new-db path)
old-in (get-in old-db path)
changed-in? (and (contains? (rf/get-effect context) :db)
(not (identical? new-in old-in)))]
(if changed-in?
(rf/assoc-effect context :dispatch [:save-to-local-storage new-in])
context)))))
Almost - assoc-effect
will override any existing :dispatch
. So instead you want to add another :dispatch
vector to the :fx
effect (if it exists - otherwise, just create it yourself). Something like (conj (or (rf/get-effect ctx :fx) []) [:dispatch [:save-to-local-storage new-in]])
.
Ah, I totally overlooked that.
When looking for localStorage
usage in re-frame I found that https://github.com/day8/re-frame/blob/ecb756e66fe30efca896879369a420df1e271605/examples/todomvc/src/todomvc/db.cljs#L61 uses ahttps://github.com/day8/re-frame/blob/ecb756e66fe30efca896879369a420df1e271605/examples/todomvc/src/todomvc/events.cljs#L68 to just directly write to localStorage
without adding another event and effect in between. Since it is in the official example I guess that is the way it should be done? Is there a downside to have side-effecting code in an interceptor?
New version:
(defn save-path-to-local-storage
[path]
(rf/->interceptor
:id :save-path-to-local-storage
:after (fn [ctx]
(let [new-db (rf/get-effect ctx :db)
old-db (rf/get-coeffect ctx :db)
new-in (get-in new-db path)
old-in (get-in old-db path)
changed-in? (and (contains? (rf/get-effect ctx) :db)
(not (identical? new-in old-in)))]
(when changed-in?
(.setItem js/localStorage :annotation (pr-str new-in)))
ctx))))