This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-09-07
Channels
- # 100-days-of-code (1)
- # announcements (10)
- # aws (2)
- # beginners (134)
- # calva (25)
- # cider (29)
- # cljs-dev (43)
- # clojure (130)
- # clojure-dusseldorf (3)
- # clojure-italy (27)
- # clojure-nl (48)
- # clojure-spec (32)
- # clojure-uk (63)
- # clojurescript (75)
- # core-logic (5)
- # cursive (18)
- # datascript (2)
- # datomic (37)
- # emacs (5)
- # figwheel (13)
- # figwheel-main (55)
- # graphql (1)
- # java (7)
- # jobs (11)
- # jobs-discuss (19)
- # juxt (1)
- # leiningen (16)
- # luminus (10)
- # mount (3)
- # off-topic (40)
- # om (1)
- # onyx (1)
- # pedestal (7)
- # re-frame (40)
- # reagent (81)
- # ring (2)
- # shadow-cljs (32)
- # spacemacs (5)
- # testing (1)
- # tools-deps (48)
Hey all, I’m confused why when I click that button the visible state is not toggling, am I missing something?
@joshua.d.horwitz yea you need return a function inside your let block
check out https://github.com/reagent-project/reagent/blob/master/doc/FAQ/ComponentNotRerendering.md
this may be helpful too https://github.com/reagent-project/reagent-cookbook/tree/master/basics/component-level-state
but the basic answer to why that’s happening is that when you click the button, the visible
ratom gets changed, causing the component to re-render, which causes the visible
ratom to get re-initialized
if you return a function instead of a vector, reagent treats that as a special case and only re-runs the returned function (rather than the whole thing). this preserves your let block
Thank you!
I'm getting into writing macros and perhaps this is more of a question about them than reagent, but why does this work: (defmacro test [& args] [:div "hello word"]) and this doesn't: (defmacro test [& args] `(r/create-class {:reagent-render (fn [_] [:div "hello world"]) })) ? I'm confused
A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
Hi, I am stuck on a 'normal' react problem (just JS no unfortunately) and I was wondering if there is anyone who might be able to help?
the state of my component updates sometimes... but I can't see how/what/where/when etc.
console.log! 🙂
add logging to the constructor fn and the render fn, possibly unmount as well
think about what can cause a component to rerender (props changes, this.state changes, or explicitly calling render)
“What” should be simple to find since there are only two ways to alter a component state
jinx! 🙂
React is very logical so the scientific method (and read the React docs) goes a long way
omg, I just don't understand why this doesn't work: (defmacro with-test [] `(r/create-class {:reagent-render (fn [] [:div "hello world"]) }))
how are you using it? have you tried using macroexpand
to see what you are getting?
well i’m trying to try it but suddenlly my cursive repl broke so i’ll have to fix that first
yeah that's in a cljs. and macros need to be defined in a separate namespace? just reading https://cljs.github.io/api/cljs.core/defmacro
yea that won’t work. the clojurescript compiler is a clojure program, so your macros also have to be clojure
because i only have a couple of macros, i just create a macros.clj
file in my project and dump them there. then i do a (:require-macros [my-ns.macros :refer [my-macro])
you can do this funky thing to simplify the ns form when you require them but I don’t bother
yeah that's it, works fine. yeah the docs are there but just have to find the right one...
makes perfect sense given macros are compile time constructs but I wish something, like figwhel would flag it as an error if you try defmacro in cljs namespace
it’s actually strange--if it finds a defmacro in a cljs i don’t know why it doesn’t throw a clear error
argh this macro stuff is a quite bit more involving than I thought.. this macro blows up if I put anything in the finally block: (defmacro with-client-rect [client-rect-atom f] `(r/create-class {:component-did-mount (fn [this#] (reset! ~client-rect-atom (common/get-client-rect (r/dom-node this#)))) :reagent-render (fn [] (r/with-let [this# (r/current-component) resize-handler# #(reset! ~client-rect-atom (common/get-client-rect (r/dom-node this#))) _# (.addEventListener js/window "resize" resize-handler#)] [:div "hello world"] (finally ;(println "hello") ;(.removeEventListener js/window "resize" resize-handler#) ))) }))
not that there’s anything wrong with experimentation, but I have a very strong feeling that you don’t need macros
for what it is worth, i’m quite surprised that with-let
works inside a render function
i mean i guess it works but the docs introduce it as a kind of substitute for form-2
yeah the whole issue why I need a form-3 is because I can't use r/dom-node inside r/with-let (because it runs in a render function)
but back to your problem, i’d suggest composing functionality using react’s component architecture instead of reaching for macros. it’s a nightmare to do things with macros
like, it looks like you are trying to wrap the resize functionality, so i’d suggest that you do that using your form-3, then pass a render prop or something like that
I'm noticing 🙂 wanted to try it though because to me it looked like a straight template function case from the outset
the rule of thumb i have is I only reach for macros when I say, “I wish this had better syntax”
macros are only helpful when you need to prevent evaluation. i don’t think you need that
what I try to do then is create a function, call it with-client-rect*
, and do all the implementation in there.
yeah could do that. but for the issue in hand... do I need to do something special for try-catch-final blocks in a macro?
I don’t really know how the with-let macro is implemented. it seems like you should be using react lifecycles directly anyway
yea agreed. the with-let
is super confusing here. just deal with it in component-will-unmount
r/with-let is super handy for keeping a reference to the resize handler function so I can clean it up. the lifecycle function don't quite allow that
(r/create-class
{:component-did-mount
(fn [this#]
(set! (.-resizeHandler this#)
#(reset! ~client-rect-atom (common/get-client-rect (r/dom-node this#))))
(.resizeHandler this#)
(.addEventListener js/window "resize" (.-resizeHandler this#)))
:component-will-unmount
(fn [this#]
(.removeEventListener js/window "resize" (.-resizeHandler this#)))
:reagent-render
(fn []
[:div "hello world"])
})
haven’t tested it, but you can set properties on JS objects like the reference that gets passed into the create-class lifecycles just like in JavaScript
you could also use an atom and a closure like justinlee said:
(let [resize-handler (atom nil)]
(r/create-class
{:component-did-mount
(fn [this#]
(reset! resize-handler
#(reset! ~client-rect-atom (common/get-client-rect (r/dom-node this#))))
(@resize-handler)
(.addEventListener js/window "resize" @resize-handler))
:component-will-unmount
(fn [this#]
(.removeEventListener js/window "resize" @resize-handler))
:reagent-render
(fn []
[:div "hello world"])
}))
yea i was thinking of something like:
(defn with-client-rect
[client-rect-atom child]
(let [ref (r/atom nil)
resize-handler (fn [] (reset! client-rect-atom (common/get-client-rect @ref)))]
(r/create-class
{:component-did-mount
(fn []
(resize-handler)
(.addEventListener js/window "resize" resize-handler))
:reagent-render
(into [:div {:ref #(swap! ref %)}]
child)
:component-will-unmount
(.removeEventListener js/window "resize" resize-handler)})))
;[with-client-rect atom [child-node]]
ok thank you both @lee.justin.m and @lilactown. still don't understand why the finally doesn't work - maybe it's the inner macro that throws it off. it's fascinating to me that the macro arguments are passed as unevaluated but having read all the warnings about not using macros too much so I had never tried writing one. so wanted to try it out but I agree, just a plain function will suffice