This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-05
Channels
- # announcements (1)
- # babashka (5)
- # beginners (151)
- # calva (43)
- # clj-kondo (23)
- # cljdoc (1)
- # cljs-dev (6)
- # cljsrn (10)
- # clojure (60)
- # clojure-australia (1)
- # clojure-europe (26)
- # clojure-gamedev (14)
- # clojure-nl (1)
- # clojure-spec (10)
- # clojure-uk (80)
- # clojurescript (66)
- # clojureverse-ops (4)
- # community-development (7)
- # conjure (8)
- # datomic (15)
- # deps-new (1)
- # docker (27)
- # emacs (2)
- # fulcro (13)
- # honeysql (13)
- # java (5)
- # jobs-discuss (43)
- # lsp (121)
- # luminus (13)
- # malli (1)
- # off-topic (73)
- # pathom (12)
- # polylith (29)
- # practicalli (4)
- # re-frame (35)
- # reagent (44)
- # remote-jobs (5)
- # rewrite-clj (2)
- # sci (7)
- # shadow-cljs (125)
- # sql (4)
- # tools-deps (9)
- # xtdb (5)
I'm elbow deep in some re-frame/reagent machinery and could use some insight if anyone has some
what I'm seeing is that when I deref a re-frame subscription, dependent subscriptions are run twice
(rf/reg-sub
:greeting
(fn [_ [_ name]]
(js/console.log "in greeting")
(str "Hello, " name)))
(rf/reg-sub
:excited-greeting
:<- [:greeting]
(fn [greeting _]
(str (string/capitalize greeting) "!")))
@(rf/subscribe [:excited-greeting])
this prints "in greeting"
twicenow, this changes if I wrap the deref of the subscription in a ratom context:
(binding [reagent.ratom/*ratom-context* #js {}]
@(rf/subscribe [:excited-greeting]))
this only prints "in greeting"
once 😵now I'm writing a React hook to use with reactions/subscriptions, so this is relevant for app development since there's not a ratom-context set when rendering a plain React component
I could set one like I have, but I really have no idea what effect it has other than not double computing on initial computation
also, initially I wrote the hook to use add-watch
& remove-watch
to subscribe to the reaction. however, changes were not propagated until I wrapped it in a *ratom-context*
I don't mind wrapping it but I'm worried I may be introducing a memory leak somewhere. the reaction code is such a hairy nest it's hard for me to keep track of what uses which
Regarding double subscription evaluation - probably this? https://github.com/day8/re-frame/issues/657
Hi guys, I am completely beginner with Reagent and I was wondering how do I translate the React props of a component to reagent functions? For example
function MyDialog() {
let [isOpen, setIsOpen] = useState(true)
return (
<Dialog open={isOpen} onClose={() => setIsOpen(false)}>
</Dialog>
)
}
This component has isOpen
prop and a callback that changes the state how can I write that in idiomatic reagent?(defn my-dialog
[]
(let [open-state (r/atom true)]
(fn []
[:> Dialog
{:open @open-state
:onClose #(reset! open-state false)}])))
Assuming Dialog
is imported like
["my-dialog-npm-thing" :refer [Dialog]]
probably worth reading this https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md#form-2--a-function-returning-a-function
And you can replace let
with r/with-let
to avoid having to wrap the Hiccup in another (fn [] ...)
.
Just like here: https://clojurians.slack.com/archives/C03S1L9DN/p1628154977190700?thread_ts=1628093560.161400&cid=C03S1L9DN
Hey folks, I have a question. I'm extending a React library to have a Tooltip and a Button element. The Tooltip documentation says: > Please ensure that the child node of Tooltip accepts onMouseEnter, onMouseLeave, onFocus, onClick events. So, if I wrap the Button in a function to create a Reagent component, the tooltip doesn't work. Does someone know how to explain to me why, please?
;; Here the tooltip work on the button
[:> Tooltip {:title "Foo Bar"}
[:> Button "Hover me!"]]
(defn wrap-button [text]
[:> Button text])
;; But here the tooltip doesn't work
[:> Tooltip {:title "Foo Bar"}
[wrap-button "Hover me!"]]
It might be because the underlying library clones the React element and adds those events to it.
@U9VP9VCE6 Reagent does that automatically since it's all Hiccup anyway.
> It might be because the underlying library clones the React element and adds those events to it. If that's the case, shouldn't it work out of the box?
I mean, under the hood wrap-button
is a React component
No, because it doesn't exist in the actual DOM and it doesn't propagate its props to Button.
I would just go through the source code of Tooltip
to be sure. The answer is definitely there.
Got it.
@U2FRKM4TW nice guest (🎩 off ) https://github.com/ant-design/ant-design/blob/70699fc711bc6f63dfcb864c49f89aeb62e29e58/components/tooltip/index.tsx#L265
hmm, I cannot think of a way to make reagent reactions work w/ React concurrency w/o introducing the double compute problem w/ re-frame subs, leaking memory or showing an initial nil
value
(defn use-reaction2
[reaction]
(let [inner-reaction (hooks/use-ref nil)
cb (hooks/use-ref identity)]
(hooks/use-subscription
(hooks/use-memo
[reaction]
{:get-current-value
(fn []
(if-some [ir @inner-reaction]
@ir
(ra/run-in-reaction
#(deref reaction)
inner-reaction
"current"
(fn [_] (@cb))
{})))
:subscribe (fn [callback]
(reset! cb callback)
#(r/dispose! @inner-reaction))}))))
this is my current iteration.
the problem this version has is if the component calling this gets rendered with a reaction
it hasn't seen before (i.e. mounting), and then that render is thrown away (so it doesn't run :subscribe
or the cleanup function returned by it) then the inner-reaction that gets created in :get-current-value
won't be disposedwhich will leak memory, since it will persist in the watchers of the reaction
passed in
this doesn't happen in the current stable version because it synchronously renders components, but w/ React Concurrency it may interleave renders based on different events and end up throwing away a render that is determined to be unusable after committing a different render
(defn use-reaction
[reaction]
(let [inner-reaction (hooks/use-ref nil)
cb (hooks/use-ref identity)]
(hooks/use-subscription
(hooks/use-memo
[reaction]
{:get-current-value
(fn []
(if (some? @inner-reaction)
@reaction
(ra/run-in-reaction
#(deref reaction)
inner-reaction
"current"
(fn [_] (@cb))
{})))
:subscribe (fn [callback]
(reset! cb callback)
#(r/dispose! @inner-reaction))}))))
the reaction constructed by make-reaction
I guess never gets its state updated, it's always nil
this essentially replicates what Reagent components do on render within get-current-value
you could have a sentinel object which has a reference to the reaction returned by run-in-reaction
, and when that object is GC'd call dispose!
on that reaction