Fork me on GitHub
#re-frame
<
2015-07-24
>
colin.yates09:07:31

hi all - just a recommendation for https://github.com/Day8/re-frame/wiki/Debugging if you haven’t seen it already.

colin.yates09:07:30

and a tip which caused pretty much my entire page to re-render everytime, for anything: (= (fn [] {}) (fn [] {})) is false

mikethompson09:07:22

Hey! That's still a top secret work in progress simple_smile

colin.yates10:07:38

@mikethompson: simple_smile

colin.yates10:07:30

if anybody wants to answer (my post at) https://groups.google.com/d/msg/clojurescript/Hzv0m4Zag_4/w2q0YYIl3lcJ then I will put it into a wiki doc as I think it is a common use-case which I can’t see an obvious answer to.

profil10:07:27

@colin.yates: How would you compare functions? If you give pure functions arguments and compare the result, sure, but otherwise? 😄

colin.yates10:07:47

my point was not to include anonymous fns in a map. I often want to pass callback handlers to generic components (generic-comp {:handler #(println “woot”)}). This will cause it to always be evaluated as the data is never equal.

colin.yates10:07:42

the answer is (defn handler [_] (println “woot”)) (generic-comp {:handler handler})) as (= handler handler) is true

colin.yates10:07:49

(is that what you were referring to?)

profil10:07:40

A named function is equal to itself yes simple_smile

profil10:07:12

s/named/symbol to a/

colin.yates10:07:07

yes, exactly. I don’t understand why inline fns aren’t - some deep internal compiler quirk maybe?

mikethompson10:07:47

I wouldn't be doing this:

(defn table-row [_]
  (fn [raw-row]
    (let [decorated-row (subscribe [:decorated-row (row)]
      [:tr [:td (:manager-desc @row)]])))

profil10:07:31

@colin.yates: (let [f1 (fn [] "asd")] (= f1 f1)) is true

mikethompson10:07:46

That creates a subscritpion on every renender

colin.yates10:07:06

@profil sure - but you are comparing symbols not inline fns then

profil10:07:27

There is no way to compare functions, inline or not

colin.yates10:07:55

@profil - I think we are in agreement simple_smile

colin.yates10:07:18

thanks @mikethompson - what would be your alternative?

profil10:07:32

The readme says: "subscriptions can only be used in Form-2 components and the subscription must be in the outer setup function and not in the inner render function. So the following is wrong (compare to the correct version above)"

profil10:07:58

so the let must be outside the fn

mikethompson10:07:29

(defn table-row [row-id]
  (let [row   (subscribe  [:row-for row-id])]
     (fn []
        [:tr   {:key row-id}  [:td  (:manager-desc @row)]]))

mikethompson10:07:44

Something like that

profil10:07:50

the returned function will be used as the render function, which will call subscribe on each render

colin.yates10:07:09

ah OK - I had mistakenly thought form 2 fns were only called once regardless of data, not once per instance of data!

mikethompson10:07:12

1. pass in the id 2. subscribe based on the id 3. make sure you put on a :key

colin.yates10:07:24

I mistakenly interpreted "called once to initialise the component”. I see. Yes, all makes sense now.

colin.yates10:07:36

thanks both - you won’t believe how much angst I have had over this!

colin.yates10:07:13

is “called once to initialise each instance of the component” more accurate?

profil10:07:54

yeah I guess, for each component of that type, it is called

colin.yates10:07:01

the other part that misled me is "Remember, that outer function is only called once. So its parameters hold the initial set of parameter values. "

colin.yates10:07:37

I took “initial set of parameter values” to mean the very first set of parameters it was ever called with (so the very first row-id in Mike’s example).

profil10:07:57

Ah, you mean like a memoizing function?

colin.yates10:07:08

@mikethompson: would you mind a PR?

profil10:07:18

Nope, its a simple closure, run for each "instance" of the component

mikethompson10:07:45

Sure. Or even something in the FAQ?

colin.yates10:07:59

I will do both - thanks a bunch guys, really.

mikethompson10:07:08

Or amendments to the "Creating Reagent Components" Wiki

mikethompson10:07:55

Note point 3, above ... :key is important

colin.yates10:07:34

because that defines an instance of a component?

mikethompson10:07:27

Hmm. I'm sitting here puzzling about how to explain this

mikethompson10:07:02

The answer is yes ... the key will link the component with the particular row id

colin.yates10:07:08

(I am under the weather with a temperature so it may well be me being a numpty ;-))

profil10:07:56

Oops, thats not the same key is it?

profil10:07:59

nvm me then

mikethompson10:07:23

Notice that the subscribe is for a certain id.

mikethompson10:07:45

We then want to make sure that same id is put on the component (via the :key)

colin.yates10:07:03

right. My brain is still used to thinking in terms of Java classes which I think is insufficient to model the various lifecycles and relationships going on here.

mikethompson10:07:41

I think about subscriptions like I do a database select

mikethompson10:07:58

I pass in the "parameters" for the select

mikethompson10:07:39

select from managers where id=12 I see this as (subscribe [:manager 12])

mikethompson10:07:22

I have to head off

mikethompson10:07:32

Before I go ... useful tip ....

mikethompson10:07:57

(defn table-row [row-id]
  (let [row   (subscribe  [:row-for row-id])]
     (fn []
        [:tr   {:key row-id}  [:td  (:manager-desc @row)  (edn->hiccup   @row)]]))   ;;  <-------

mikethompson10:07:13

See that (edn->hiccup @row) bit that I added

colin.yates10:07:52

oh that is nice.

mikethompson10:07:22

Thanks @yogthos (library) and @escherize (concept for using it)

colin.yates15:07:19

Continuing the discussion about subscriptions and stitching together data I have created https://github.com/yatesco/re-frame-stiching-together

colin.yates15:07:37

Thoughts, feedback etc. most welcome (I have a bit of a virus at the moment so go gentle :))

Petrus Theron15:07:21

Attempting so subscribe to a keyword with more than one slash seems to be throwing: clojure.lang.ExceptionInfo: Invalid token: :materials/load/response. I presume this is cljs limitation?

colin.yates16:07:28

@petrus I think that is a problem with namespacing; :a/b is a keyword 😛 in namespace :a.

colin.yates16:07:43

I work around this by :a/b_c

mikethompson18:07:06

@colin.yates: That's a useful repo, thanks! I don't have enough time to properly comment. Under the pump. But I added an assert below ... just to check on something.

(defn style-4-row [fruit-id]
  (let [decorated-row (re-frame/subscribe [:style-four/decorated-row fruit-id])]
    (fn [new-fruit-id]
      (assert (= new-fruit-id fruit-id))   ;;    <--  added
      (.log js/console "style-4-row for " (clj->js @decorated-row))
      [table-row @decorated-row])))

colin.yates18:07:02

my understanding/assumption is that that equality will always be true - is that your intention?

mikethompson18:07:32

I'm thinking more about the time that someone deletes the first fruit, and all the components shuffle "up" by one

colin.yates18:07:57

ah ok, in my example they are domain ids not indexes so that shouldn’t be a problem?

mikethompson18:07:59

Being paranoid

mikethompson18:07:44

Remember the subscription is based on the INITIAL value of fruit-id (in value in the outer)

mikethompson18:07:54

But thereafter, on each render, a new value could be supplied EXCEPT you supply a :key on the component. So the id in the inner render should always match the outer

mikethompson18:07:31

This is more likely a concern when the list of fruit is more dynamic, or reordered.

mikethompson18:07:59

Uggh. Head full. Not explaining very well sorry.

colin.yates18:07:02

np, I think I see what you mean. I can see this working only if that id never changes, hence the domain id not ordinal id. The {:key} is necessary to maintain that association?

mikethompson18:07:27

Yeah. Let me put it this way: 1. We subscribe based on the INITIAL id passed in 2. So we'd better make sure that later, on each render, we think we are still rendering that same id. 3. We believe we will be because we supply a :key on each row component. 4. But that assert is me being paranoid.

colin.yates18:07:13

yep, understood. I think I should add that explanation to the various edits on the wiki I made earlier and update my repo as well.

colin.yates18:07:03

will do that tomorrow (got to run now).

colin.yates18:07:25

np and my pleasure. I feel bad I don’t have more time to contribute to open source, so no need to thank me at all simple_smile