This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-01-16
Channels
- # beginners (11)
- # boot (21)
- # cider (12)
- # clara (6)
- # cljs-dev (7)
- # cljsjs (1)
- # cljsrn (62)
- # clojure (137)
- # clojure-austin (5)
- # clojure-italy (1)
- # clojure-nl (2)
- # clojure-russia (46)
- # clojure-spec (21)
- # clojure-uk (79)
- # clojurescript (56)
- # clr (1)
- # core-typed (1)
- # css (1)
- # cursive (3)
- # datomic (35)
- # docker (2)
- # emacs (20)
- # garden (3)
- # hoplon (8)
- # incanter (3)
- # jobs (12)
- # mount (5)
- # nginx (1)
- # off-topic (71)
- # om (8)
- # om-next (6)
- # onyx (4)
- # perun (3)
- # proton (2)
- # protorepl (5)
- # re-frame (35)
- # reagent (38)
- # ring (5)
- # ring-swagger (12)
- # rum (35)
- # spacemacs (2)
- # specter (5)
- # test-check (6)
- # yada (52)
I think my workaround will be "callback updates state to request page of results be loaded"
Can someone help me out with a question that I'm not sure how to ask... Sometimes using the metadata :key works well eg:
(defn list-by [entities sort-k]
[:ul
(for [[k v] (sort-by (comp sort-k val) @entities)]
^{:key k}
[:li (:name v)])])
But sometimes it doesn't, eg:
(def words
["ice" "cream" "chocolate" "pastry" "pudding" "raspberry" "mousse"
"vanilla" "wafer" "waffle" "cake" "torte" "gateau" "pie" "cookie"
"cupcake" "mini" "hot" "caramel" "meringue" "lemon" "marzipan" "mocha"
"strawberry" "tart" "custard" "fruit" "baklava" "jelly" "banana" "coconut"])
(defn rand-name []
(string/capitalize (string/join " " (take (+ 2 (rand-int 5)) (shuffle words)))))
(def desserts (reagent/atom ()))
(defn make-a-dessert [e]
(swap! desserts conj {:id (random-uuid)
:name (rand-name)}))
(defn make-many-desserts [e]
(dotimes [i 100]
(make-a-dessert nil)))
(defn color-for [x]
(str "#" (.toString (bit-and (hash x) 0xFFFFFF) 16)))
(defn dessertinator []
[:div
[:button {:on-click make-a-dessert} "Invent a new dessert"]
[:button {:on-click make-many-desserts} "Invent 100 new desserts"]
[:ol
(for [{:keys [id name]} @desserts]
^{:key (doto id (js/console.log))}
[:li
[:svg {:width 50 :height 50}
[:circle
{:r 20 :cx 25 :cy 25 :fill (color-for id)}]
[:rect {:x 15 :y 15 :width 20 :height 20 :fill (color-for name)}]]
[:span [:em [:strong name]]]])]])
putting it as a {:key id} attribute works fine
But I don't really understand the rules for when the metadata form works and does not work.
(defn f []
[:ol
(for [d @desserts
:let [_ (js/console.log (:id d))]]
^{:key (:id d)}
[dessert d])])
(defn dessertinator []
[:div
[:button {:on-click make-a-dessert} "Invent a new dessert"]
[:button {:on-click make-many-desserts} "Invent 100 new desserts"]
[f]])
does work...so it seems to be related to the structure of the component
i.e.: if metadata is attached deeper than level 2 it doesn't seem to "work" (sorry for the hand wavy language)
So in your last example, if you wrap f
s ol hiccup in a button (instead of doing it in desertinator) it stops working?
hmmm great question. I just tried wrapping it in a :div, and it didn't produce a warning, so my theory is clearly wrong 🙂
oh I bet I know what the issue is....
its a klipse specific thing nevermind lol
Wouldnt think it would matter, but in your failing example, if you move the console.log from the metatdat and place it in the for
let block .. does that change anything?
So klipse reagent code has a slight detail where the LAST form is a little special
if I just define my dessertinator as the 2nd last form, it's fine.
yup that's it
Thanks for the sanity check!!! 🙂
(defn transition-test [component]
[TransitionMotion
{:styles (if component
[{:key "panel"
:default-style {:x 0}
:style {:x (spring 100)}}]
[])
:will-enter (fn []
#js {:x 0})
:will-leave (fn []
#js{:x (spring 0)})}
(fn [x]
(reagent/create-element
(reagent/reactify-component
(fn [anim-obj]
(println anim-obj)
(when-not (empty? (anim-obj :children))
(let [x (-> anim-obj
:children
first
(gob/get "style")
(gob/get "x"))]
[:div#panel
{:style
{:transform (str "translate(" (- 100 x) "px, 0)")
:opacity (/ x 100)}}
(with-out-str (prn anim-obj))
component])
)))
#js{} x))])
It’s alive(defn Panel-child [{:keys [styles children]}]
(when styles
(let [x (.. styles -style -x)]
[:div#panel
{:style
{:transform (str "translate(" (- 100 x) "px, 0)")
:opacity (/ x 100)}}
children])))
(defn animated-panel [children]
[TransitionMotion
{:styles (if children
[{:key "panel"
:default-style {:x 0}
:style {:x (spring 100
{:stiffness 320 :damping 30})}}]
[])
:will-enter (fn []
#js {:x 0})
:will-leave (fn []
#js{:x (spring 0 {:stiffness 320 :damping 20})})}
(fn [styles]
(reagent/create-element
(reagent/reactify-component Panel-child)
#js{:styles (aget styles 0)} children))])
a little better..Can someone explain why I can't use state defined in a let with reagent? http://paste.debian.net/908989/
The only difference is the scope of the state and the contents of the let shouldn't be GC'd because it's still referenced isn't it.
@rovanion what the surrounding context - state defined in a let works fine with reagent, so something else must be awry
The surrounding context is a div. This is all:
(def chat-state (atom ""))
(defn chat []
[:div {:id :chat}
(let [chat-state (atom "")]
[:textarea
{:value @chat-state
:on-change #(reset! chat-state (-> % .-target .-value))}])
[:textarea
{:value @chat-state
:on-change #(reset! chat-state (-> % .-target .-value))}]])
This is then rendered with reagent/render
.@rovanion the problem is you have a form-1 component, but you either want to use a form-2 component or def the state outside the render fn (which you have discovered)... see https://github.com/Day8/re-frame/wiki/Creating%20Reagent%20Components for a discussion of the different component types
Thank you so much @mccraigmccraig! Returning an inner rendering function made it so that the atom isn't redefined every time the component is rendered, so that it's only defined once at the beginning so to speak.
I created a SO Q&A for posterity: http://stackoverflow.com/questions/41679787/why-is-it-not-possible-to-define-the-state-of-a-reagent-component-in-a-let/41679788#41679788
But that was all just so that I could write this other SO question: http://stackoverflow.com/questions/41680143/how-is-a-chat-input-field-defined-in-reagent It's about trying to implement a chat input text-area like that here on slack, where pressing the enter key sends the message.
@rovanion have a look at this https://www.refheap.com/065414f3f75decf0fdbe89f21
it's a stupid simple solution to overflow, but it works ok
ANN: Recently I've been working on a Reagent Toolbox library called recalcitrant: https://github.com/pesterhazy/recalcitrant. It's still early stages. But the basic idea is to make lifecycle methods composable: start with a render fn, add some side-effect, add logging, add resource management for a timer
Generally recalcitrant should help with the somewhat onerous task of building stateful components. I'd be curious if people think that could be useful
There's also a component that does Error Handling in interactive development in there, it's proven helpful when working on SPAs.
@pesterhazy looks very helpful! nice idea/tool