This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-07-17
Channels
- # beginners (42)
- # cider (1)
- # cljs-dev (20)
- # clojure (73)
- # clojure-italy (8)
- # clojure-nl (53)
- # clojure-spec (11)
- # clojure-uk (88)
- # clojurescript (170)
- # clojutre (6)
- # core-async (26)
- # css (2)
- # cursive (13)
- # data-science (10)
- # datomic (15)
- # editors (3)
- # figwheel (28)
- # figwheel-main (67)
- # fulcro (57)
- # graphql (2)
- # immutant (2)
- # jobs (1)
- # jvm (4)
- # lein-figwheel (3)
- # leiningen (1)
- # off-topic (5)
- # pedestal (28)
- # re-frame (86)
- # reagent (18)
- # reitit (8)
- # ring (3)
- # ring-swagger (2)
- # shadow-cljs (78)
- # spacemacs (10)
- # specter (12)
- # tools-deps (32)
- # vim (3)
(a) Your example needs only one unconditional child and one conditional child (maybe) to illustrate your code. This is helps us reviewers, and this helps you.
(b) make sure the top level h-box has min width and height and a nice background color as a sanity check
(c) include the parent component for device-row
(d) if nothing is rendering keep your eye open for unnoticed compilation issues. I am surprised often by dead wrong code (eg, non-existent variable references) happily executing. So scan your output closely for scary messages.
Ok, I will remember a) from now. That will make it easier for me to get the code working as well.
Parent component for device row:
(defn devices-list []
(let [sorted? (reagent/atom false)
sorted-field (reagent/atom "")
inverted? (reagent/atom false)
;; @ grabs these values from the atom, and keeps you safe from multiple
;; concurrent changes
]
(fn [] ;; needed when using multiple atoms so that things update properly
(let [devices (re-frame/subscribe [::subs/devices-sorted sorted? sorted-field inverted?])]
[v-box
:children [[h-box ...
]
;; code below pulls in the devices from device-row function
[h-box
:children [[v-box ;; Device name
:children (into []
(for [device @devices]
(device-row (:data device))))]
]]]]))))
I haven't seen any scary messages or flags in the console, in terminal, or elsewhere. I am often surprised how everything else renders fully except for a section, but there is no notice whatsoever of the problem.
This seems iffy:
(let [devices (re-frame/subscribe [::subs/devices-sorted sorted? sorted-field inverted?])] ...
Shortened device-row code:
(defn device-row [device]
(let [edit-mode? (reagent/atom false)
text-val (reagent/atom "")
status (reagent/atom nil)
status-tooltip (reagent/atom "")
]
(fn [device]
[h-box
:min-width "100px"
:min-height "100px"
:background-color "#FAEBD7"
:class "rc-div-table-row"
:width "1060px"
:gap "15px"
:children [[md-icon-button :md-icon-name "zmdi zmdi-edit"
:on-click #(do (reset! edit-mode? true)
(println "Trying to turn on edit mode"))]
(when @edit-mode? [h-box
:children [[md-icon-button :md-icon-name "zmdi zmdi-edit"
:on-click #(do (reset! edit-mode? true)
(println "Trying to turn on edit mode"))]
]])]
])))
You’re calling subscribe
and giving it a vector with 4 items: a keyword, and 3 local ratoms
which, hmm, I guess that could work, it’s just not how I normally do things
This is just me and a (very experienced programmer, but not with re-frame) friend hacking this site together
I usually have a :ui
section in my main app-db
for state that’s UI-only, like edit-vs-read mode
Then I connect them via subscriptions with input signals.
If you’re using the 10x debugger, you can see all of your subscriptions in the debug window, which can be handy for tracing flow
Oh cool, do you have an example of this? I don't have a lot of experience so it's hard for me to pick up patterns easily
Yeah, give me a minute I’ll try and re-write your example how I would normally approach it
Ok, here’s some sample code just for the subscriptions. The design trade-off is that it’s pretty boiler-platey, but what you get for that is (a) you can use 10x to see exactly how the data is flowing thru the subs and (b) I believe it minimizes unnecessary re-renders, since each nested subscription only re-triggers when its own value has changed.
Hang on, that’s too long, let me re-post as a snippet
The basic idea is each sub peels off one layer of nesting, and then becomes the input signal for the next sub
If you’re not familiar with the :<-
syntax, it’s documented in the TODOMVC example https://github.com/Day8/re-frame/blob/master/examples/todomvc/src/todomvc/subs.cljs
I like to post the link because it’s not in the main docs and sometimes people miss it.
The other gotcha is to watch your square brackets when using input signals. If you have only a single input signal, you get the data by itself, but if you have more than one, you get a vector of incoming data args
(rf/reg-sub
:foo
:<- [:bar]
(fn [bar] ;; no extra []
...))
(rf/reg-sub
:baz
:<- [:a]
:<- [:b]
(fn [[a b]] ;; double []'s!
...))
Yeah, it’s clearly written to be a tutorial/explanation and not just “what’s the minimum working code we can get out there”
@aaron993 Nice code cleanup. So are you seeing the sanity check(s)? Ie, device rows with nothing but the bg color? Do you have print statements in your actual code confirming you are even hitting various code points?
@hiskennyness Thanks! There are no sanity checks, at all. The header names render, but nothing below (i.e., the device rows)
Plz check (nil? devices)
🙂
The first line of device-row the defn could be (prn :we-have-a-device! device)
. It is possible you just are not finding the devices. And sorry, I did not realize you were a noob to programming as well; my remark on (nil? devices)
was a playful way of suggesting you might not even be hitting the code you are worried about because elsewhere you are not finding devices.
Ok thank you. I understood the meaning of (nil? devices), just not sure how to implement it
I also forget that for a lot of things in clojure, the answer is easy and obvious once you see it
Yes, the devices are being pulled in, and that is confirmed by the event window in th 10x debugger
From my limited experience with re-frame and re-com, it appears that it is an issue with formatting of my code, since it is behaving similarly to when I am missing a [] or () somewhere, and instead of throwing an error everything else just renders and the affected component doesn't
OK, so throw a block commenter #_
in front of your [hbox...]
and in front of that add [p "Hi, Mom!"]
— some form you know is right. Baby steps.
Agreed btw on this prolly being sth. simple.
I got the idea from here: https://github.com/Day8/re-com/blob/master/src/re_demo/modal_panel.cljs (specifically line 115)
We should take this to the side. 🙂
Which makes me think the problem comes from here in the devices-list function:
[h-box
:children [[v-box ;; Device name
:children (into []
(for [device @devices]
(device-row (:data device))))]
]]]
So all your print statements are firing and you see no “Hi mom”? Do you have the browser debugger open so you can see if anything is going wrong during rendering? That is my favorite thing to forget checking.
Update: When I remove the (fn [devices]) from everything, "Hi Mom" show's up for every device listing
@aaron993 I’m guessing you’ve modified the code some since we last talked, here’s a sample pattern I use a lot:
(defn sample-comp
[]
;; Before the (fn), do the subscription
(let [my-sub (rf/subscribe [:some-subscription])]
;; The (fn) is the rendering function we return to re-frame
(fn []
;; Inside the (fn), dereference the subscription
(let [my-data @my-sub]
;; Add a debugging step to check if we're getting the right data
(prn {:my-data my-data})
;; Use the data to render the stuff we want
[:div (:some-value my-data)]))))
Does your code look like that?
Especially where you do the subscribe
as compared to where you actually de-reference the subscription (with @
) and use the data.
@manutter51 I spent the morning after we talked helping a friend move, so I haven't gone too far through the information that you sent me yet. I have mostly tried to figure out why the inner render function won't actually render, but I'm stuck on that. So next is going through what yo uhave sent
ok, good enough then 🙂
I am going to go back to a working copy that renders, then adjust my code to fit your pattern directly above, then start looking through the docs that you sent me earlier (with the :<-
Yeah, i think so. Mostly I was just reading the scrollback and it looked like you were still having issues, so I thought I’d throw that in as something else that might help
The important bit is that the let
before the fn
happens one time, when re-frame is setting up your component, and the let
after the fn
happens every render
So you want the subscribe
to be in the first let
(so you only subscribe once), and the you want to dereference the subscription in the let
after the fn
, so you get fresh data every render.
What is the difference between having the subscribe be in the second let, and dereferencing it in the second let instead?
I’ll use an analogy to disguise the fact that I’m not too familiar with the inner workings here 😉 But the basic idea is that subscribe
is a setup step, like turning on wifi, so you do that one time before you start
Then, when you do @some-subscription
in the second let
, it’s like browsing the web (i.e. pulling data down via the wifi)
So you could make a new wifi connection every time you click on a link, but you probably don’t want to — set it up one time, and then pull data from it.
That’s my understanding at least
Okay I moved the subscribe up to the outer let statement and placed in [device @devices] in the inner statement and everything still functions.
:thumbsup: