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)
hey all… I’ve got a question to check my understanding. I have a component that creates a point on a chart. when I drag the point around I want it to update some state in a reagent atom. BUT, nothing about its properties depends on the atom value. still, the component is trying to re-render every time it successfully updates the state, which forces its position back to the initial spot.
the first point triggers an update; I only want the SECOND point to re-render, but I am seeing :component-did-update
called in both points
this is a touch convoluted since I’m using it with #C035GRLJEP8 but here is the code for the component https://github.com/sicmutils/sicmutils-clerk/blob/sritchie/mathlive/src/demo/jsxgraph.cljs#L92-L146
and then for the parent component: https://github.com/sicmutils/sicmutils-clerk/blob/sritchie/mathlive/src/demo/jsxgraph.cljs#L21-L72
I think what is happening is that the JSXGraph2 component is re-rendering constantly… which actually STOPS happening when I take away the call to [v/inspect @!state]
. that is surprising since it looked like that was a parallel component in the tree.
so concretely —
1. why does the deref of !state
passed to v/inspect
cause a re-render of JSXGraph2
and all of its children?
2. is there some way I can stop this, if this is expected behavior?
> nothing about its properties depends on the atom value
Right, but the containing component does depend on the ratom's value.
And the first Point
gets re-rendered because you pass it a different :on-drag
every time the containing component's view function is called. After all, (not= #() #())
.
> Right, but the containing component does depend on the ratom’s value.
>
> because everything is wrapped in with-let
?
> And the first Point
gets re-rendered because you pass it a different :on-drag
every time the containing component’s view function is called. After all, (not= #() #())
yeah, that is why I was hoping to short circuit by having the containing view
not be called in this case. Sorry I’m feeling dense; @U2FRKM4TW, which is the containing component here that depends on the ratom’s value:? The :<>
, because one of its children does?
> because everything is wrapped in with-let?
Because you deref the ratom within the component's view function. Doesn't matter if the value is used at all - what matters is the fact of deref'ing the ratom.
> which is the containing component here that depends on the ratom’s value:?
By the "containing component" I meant the one in the code block, the function. Not any particular Hiccup vector.
You can try moving that lambda from that Point
and into with-let
.
And same should probably be done with the lambdas in the second point. But depends on what exactly points do internally.
wow, moving those functions to with-let solves this!
okay, that helps. I was fighting inside my component-did-update
etc functions to prevent my points from getting removed and re-added to the scene, but this is more clear; the function values need to stop changing (ie getting created on every render) and then no more fight needed
is there by any chance some wrapper @U2FRKM4TW that STOPS the re-render propagation on deref
actually nm, I can rework this to avoid the user having to pass functions
Sure - pass the ratom itself into a Hiccup vector and deref it only within the component that the vector uses.
but for example if I want the component to update some key in the ratom, I think the way I have to do it @U2FRKM4TW is to pass the ratom AND a key, and then have the function internally build an update-fn in a with-let
hey all - for my custom component, if I want to pass something back into a :ref
key that the user supplies, there is no special react machinery for that, right? I just look for a :ref
prop and handle it?
I guess the question is, what are the “rules” on when a ref should be called; in render? in component-did-update? etc
This comes up in the stateful library from my question above. I have components that add some stateful thing (like a point) to the scene based on declarative arguments to the component; BUT, sometimes I need to get at the internal state of the stateful thing from some other component. For points I have been using an event listener to have them push their new positions into a ratom on a “drag” event; but some other components don’t emit events. Like an “integral” component that integrates under a curve.
SO my thought was if I could call “ref” then I could push the whole “integral” stateful piece into a ratom once and query it there from other components
I was under the impression is called when the component is first attached to the dom, since I will often use it to do things like get the height and width or x/y offset of the element
My unsolicited suggestion though is that may want to consider that the event which caused the component to come in to existence in the first place, Event = State->State’, therefore View -> View’ (assuming the component is mounted in State’), you would want E to transmit that data to the external atom rather than have the update function of the component do it. I often find myself surprised at how much these things remount and engineering the update functions to be idempotent with respect to a debounce period can be quite challenging. And even if you get it right initially, if you change something upstream and you forgot about your update logic, it may start to operate outside design spec.
@U3BALC2HH yes of course you’re right. the issue I’m trying to resolve is that the underlying library almost requires at this point that I remove-and-re-add elements like Point
, Angle
etc any time their properties (color, x-y coordinate functions etc) change.
so if you want to, say, query a point’s x-y coordinates every time it changes, you can either
• get the point via ref, and update your reference every time :ref
is called and the underlying point changes
• register a callback that gets the currently-in-play point as an argument…
I am thinking the second one is best, since then I never have to worry about the user hanging on to stale references.
ahhh okay so the underlying library is procedural construction rather than "React"-ive, got it. No, wait, :ref
wouldn't apply here then :thinking_face:
or are you putting a reactive wrapper on it?
yup, putting a reactive wrapper around it @U3BALC2HH
Ahhh ok. So does the change data event propagate from the underlying library or do you control the bookkeeping? If you control the bookkeeping, one kinda hacky but easy to implement reactive Sussman-style propagator that's easy to implement is:
(def my-data (atom {}))
(def my-data-rx (reagent/atom {})) ;; this could be global application state, whatever
(defn mirror-changes [f]
(add-watch my-data ::mirror-changes
(fn [_ _ _ new-data]
(swap! my-data-rx f new-data))))
(defn my-graph-data (reagent.ratom/make-reaction #(graph-data-of @my-data-rx))
then your event logic should update my-data
and send a message to the underlying library, and the propagator should do the work of updating the reactive part of your app state
it's way easier to suggest solutions to other people than buckle down and do my own work so thanks for humoring me
@U3BALC2HH the events come from the underlying library, but there is an update
event emitted by the board every time anything changes that I think I can use to good effect
haha anytime! thank you! this is helpful for sure. a night of sleep on the problem was helpful too…