This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-28
Channels
- # announcements (2)
- # babashka (16)
- # bangalore-clj (1)
- # beginners (93)
- # boot (11)
- # calva (5)
- # cider (13)
- # clj-kondo (49)
- # cljdoc (14)
- # cljs-dev (1)
- # clojure (99)
- # clojure-dev (3)
- # clojure-europe (1)
- # clojure-india (1)
- # clojure-italy (9)
- # clojure-nl (3)
- # clojure-poland (1)
- # clojure-russia (1)
- # clojure-spec (31)
- # clojure-uk (21)
- # clojured (2)
- # clojurescript (18)
- # core-async (12)
- # cursive (36)
- # data-science (1)
- # datomic (54)
- # duct (3)
- # emacs (33)
- # events (1)
- # fulcro (17)
- # jobs (1)
- # joker (8)
- # keechma (1)
- # leiningen (7)
- # malli (8)
- # nrepl (19)
- # pathom (6)
- # planck (18)
- # re-frame (20)
- # reagent (18)
- # shadow-cljs (3)
- # sql (7)
- # vim (31)
I'm trying to understand the internals a little better, because I'm seeing unexpected behavior. I'm calling dispatch-sync to update a value in my app-db. I'm calling this on willMount. A child component then subscribes to this data. However, on first render it shows the old value, then a re-render happens with the new value. This is problematic as the child component stores the first value it sees into a local atom for UX-related post-processing. Am I missing some important incantation, or is this simply how reframe works?
It might be related to order of events happening. I'd try to log every related event, like mount and dispatch, for all components.
I logged: - After dispatch-sync - After subscription deref (which is in render) Order is: - dispatch-sync - subscribe (old value) - subscribe (new value)
I’m guessing that although dispatch-sync runs the event handler synchronously, the recomputation of the subscriptions is not done as part of that synchronous block, so the subscribe in the child will see the cached value on its first render
can you move the will mount logic outside of the component, and choose whether to show the component based on a subscription
Unfortunately not. I'm interfacing with a react component that passes a "cause trigger" in the props which I need to react to in order to change the input initial value.
I think it is not really "synchronously".
re-frame internally uses a queue
https://github.com/day8/re-frame/blob/72f06966b0e6bb40c35607629a5301ef3a9e6640/src/re_frame/router.cljc
But the dispatch-sync
skips a part of this process
https://github.com/day8/re-frame/blob/72f06966b0e6bb40c35607629a5301ef3a9e6640/src/re_frame/router.cljc#L251
I didn't dig in far enough to see what happens with the app-db from the handler-fn. I didn't check when it was actually swapped back.
I guess the intention is to provide a consistent view of the state until after the render has completed?
Can you isolate the case somehow? Like, just the parent component that fires dispatch-sync
in will-mount
and the child element that subscribes?
having dug in, I can't find anything that would imply that there's something special to make it be consistent in re-frame. So my only other conclusion would be it's clojure/reagent behavior somehow.
Okay. Looks like this is reagent behavior. I haven't quite read the source to understand the context, but a call to ratom/flush! does the trick.
I believe reagent runs ‘flush’ once per render loop (before looping through all the invalidated components and .forceUpdate’ing them), and the flush is what forces the stale subscriptions to update, so I think you have found the best path forward
interestingly, the problem @kenny @mikethompson and I discussed above about debouncing is directly related to a new API that the React team is experimenting with: https://reactjs.org/docs/concurrent-mode-patterns.html#deferring-a-value