Fork me on GitHub
#re-frame
<
2018-07-17
>
kennytilton02:07:10

(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.

kennytilton02:07:00

(b) make sure the top level h-box has min width and height and a nice background color as a sanity check

kennytilton02:07:36

(c) include the parent component for device-row

kennytilton02:07:05

(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.

Aaron11:07:15

Ok, I will remember a) from now. That will make it easier for me to get the code working as well.

Aaron11:07:00

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))))]
                                  ]]]]))))

Aaron11:07:25

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.

manutter5112:07:22

This seems iffy:

(let [devices (re-frame/subscribe [::subs/devices-sorted sorted? sorted-field inverted?])] ...

Aaron12:07:11

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"))]
                                                ]])]
       ])))

manutter5112:07:12

You’re calling subscribe and giving it a vector with 4 items: a keyword, and 3 local ratoms

Aaron12:07:35

Ahh, ok. That was working before

manutter5112:07:51

which, hmm, I guess that could work, it’s just not how I normally do things

Aaron12:07:02

What is your normal pattern?

Aaron12:07:31

This is just me and a (very experienced programmer, but not with re-frame) friend hacking this site together

manutter5112:07:16

I usually have a :ui section in my main app-db for state that’s UI-only, like edit-vs-read mode

manutter5112:07:31

Then I connect them via subscriptions with input signals.

manutter5112:07:12

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

Aaron12:07:49

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

Aaron12:07:56

I am using 10x debugger though

manutter5112:07:41

Yeah, give me a minute I’ll try and re-write your example how I would normally approach it

Aaron12:07:07

That is awesome, thank you

manutter5112:07:27

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.

manutter5112:07:20

Hang on, that’s too long, let me re-post as a snippet

Aaron12:07:20

Awesome, thank you I will look that over

Aaron12:07:31

And try to figure it out

manutter5112:07:58

The basic idea is each sub peels off one layer of nesting, and then becomes the input signal for the next sub

manutter5112:07:15

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

manutter5112:07:20

I like to post the link because it’s not in the main docs and sometimes people miss it.

manutter5112:07:12

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

manutter5112:07:36

(rf/reg-sub
  :foo
  :<- [:bar]
  (fn [bar]  ;; no extra []
    ...))

(rf/reg-sub
  :baz
  :<- [:a]
  :<- [:b]
  (fn [[a b]]  ;; double []'s!
    ...))

Aaron13:07:15

Okay that is my next task, to learn that

Aaron13:07:17

Thank you!

Aaron13:07:35

Does the TODOMVC example really explain things well?

manutter5114:07:42

Yeah, it’s clearly written to be a tutorial/explanation and not just “what’s the minimum working code we can get out there”

kennytilton16:07:24

@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?

Aaron17:07:08

@hiskennyness Thanks! There are no sanity checks, at all. The header names render, but nothing below (i.e., the device rows)

kennytilton17:07:56

Plz check (nil? devices) 🙂

Aaron17:07:01

No I do not... What would be suggestions for that?

Aaron17:07:08

How would I check for nil? Sorry, I am still fairly new to programming i ngeneral

kennytilton17:07:14

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.

Aaron17:07:36

Ok thank you. I understood the meaning of (nil? devices), just not sure how to implement it

Aaron17:07:54

I also forget that for a lot of things in clojure, the answer is easy and obvious once you see it

Aaron17:07:34

Yes, the devices are being pulled in, and that is confirmed by the event window in th 10x debugger

Aaron17:07:45

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

kennytilton18:07:23

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.

kennytilton18:07:42

Agreed btw on this prolly being sth. simple.

eggsyntax18:07:33

^-- at a glance, I assume s/p/:p/ above, but I haven't read the whole discussion.

Aaron18:07:59

Commented out the h-box and everything after, and put in the [p "Hi Mom!"

Aaron18:07:16

Same condition as before, nothing rendering below the column headers

Aaron18:07:26

And cannot find any formatting differences between my code and their code

kennytilton18:07:37

We should take this to the side. 🙂

Aaron18:07:06

Nothing changes when I take device out of the fn [] either

Aaron18:07:00

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))))]
                                  ]]]

kennytilton18:07:56

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.

Aaron18:07:38

Print statement sare firing but nothing is rendering

Aaron18:07:46

I have the 10x debugger, is there another?

Aaron18:07:14

and I have chrome dev tools of course

Aaron19:07:38

Update: When I remove the (fn [devices]) from everything, "Hi Mom" show's up for every device listing

Aaron19:07:35

So it is definitely something going on with the inner render function

ericfode19:07:50

The chrome console should have what he is referring to

Aaron19:07:49

Ok. Was checking that and nothing cryptic there

manutter5119:07:12

@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)]))))

manutter5119:07:31

Does your code look like that?

manutter5119:07:25

Especially where you do the subscribe as compared to where you actually de-reference the subscription (with @) and use the data.

Aaron19:07:57

@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

manutter5119:07:49

ok, good enough then 🙂

Aaron19:07:33

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 :<-

Aaron19:07:43

That last part will take awhile though!

Aaron19:07:03

Just to be specific, you were reffering to my devices-list function?

manutter5119:07:49

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

Aaron19:07:10

Ahh ok. I will implement that now and see if it improves anything

Aaron19:07:16

Looks like a more clean pattern anyways

Aaron19:07:28

Thank you for the help!

manutter5119:07:37

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

manutter5119:07:26

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.

Aaron19:07:32

What is the difference between having the subscribe be in the second let, and dereferencing it in the second let instead?

manutter5120:07:16

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

manutter5120:07:53

Then, when you do @some-subscription in the second let, it’s like browsing the web (i.e. pulling data down via the wifi)

manutter5120:07:34

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.

Aaron20:07:05

Ahh okay. An efficiency and render speed issue

manutter5120:07:15

That’s my understanding at least

Aaron20:07:07

Cool, thanks. I figured that was the idea behind

Aaron20:07:53

Okay I moved the subscribe up to the outer let statement and placed in [device @devices] in the inner statement and everything still functions.

Aaron20:07:07

Now time to work through the info you sent, thanks