Fork me on GitHub
#re-frame
<
2018-06-01
>
sofra00:06:32

got this working using reagent.core/track! thanks to @nenadalm

sofra00:06:03

now I can just track a subscription and produce the side effect

ackerleytng14:06:56

I'm trying to lay out little square videos in rows, and when i press + and -, i want the number of videos in each row to decrease and increase respectively

ackerleytng14:06:35

i'm using map to map a component-creating function over each video in a row, and because of that all the videos are re-rendering when i press - or +

ackerleytng14:06:48

is there a better way to do it to reduce the re-rendering?

mikerod14:06:03

@ackerleytng It may be helpful to have an example

ackerleytng14:06:10

(->> vid-objs
            vals
            (partition row-count row-count (iterate #(update % :id inc) {:id 0}))
            (map (partial video-row row-count)))

(defn video-row
  [row-count vid-objs]
  {:pre [(<= (count vid-objs) row-count)]}
  ^{:key (str/join "-" (map :id vid-objs))}
  [:div.columns
   (map (partial video-column row-count) vid-objs)])

mikerod14:06:58

You can improve that and will likely help

mikerod14:06:14

refer to video-column via vector hiccup syntax, not as a “normal” function call

mikerod14:06:31

This allows Reagent to apply conditional rendering to sub elements in the resulting hiccup

mikerod14:06:11

However, you also need to associate a :key with the components in the collection you are creating with map. This :key will allow React to assign an “identity” to the components in the collection, so it can see if any props to each one has changed or not

mikerod14:06:43

You also have to do similar with video-row

ackerleytng14:06:06

does the private map with :key help?

ackerleytng14:06:38

and how can i use map with the hiccup syntax?

mikerod14:06:53

(->> vid-objs
     vals
     (partition row-count row-count (iterate #(update % :id inc) {:id 0}))
     (map (fn [x]
            [video-row {:key (some-key-unique-to-x x)} row-count x])))

(defn video-row
  [row-count vid-objs]
  {:pre [(<= (count vid-objs) row-count)]}
  ^{:key (str/join "-" (map :id vid-objs))}
  [:div.columns
   (map (fn [vid]
          [video-column {:key (some-key-unique-to-vid vid)} row-count vid]) vid-objs)])

mikerod14:06:23

You just can’t use something like partial (at least I don’t know of a way to)

mikerod14:06:09

Reagent components are mostly “normal” functions, but you shouldn’t call them like normal functions in other components. Components generate hiccup and should interact with other nested/child components via hiccup

mikerod14:06:15

(aka vectors)

mikerod14:06:54

If you cannot come up with a :key for your case, then the positional index may be ok for your use case since I think you have + or - appending to the end only

mikerod14:06:03

so the position is actually a real identity

ackerleytng14:06:04

oh i see, you put the keys when you create the component

mikerod14:06:16

although using the position in a collection as your :key in React is generally discouraged

ackerleytng14:06:35

does the hiccup syntax work if i build a vector?

mikerod14:06:38

because if you use the index position, and then added to the beginning or middle, it’d re-render everything

ackerleytng14:06:52

like if i do something like...

mikerod14:06:00

if your component function returns vectors, they are interpreted as hiccup by Reagent

ackerleytng14:06:02

wait that's what you're doing

mikerod14:06:33

No problem. Let me know if you have other questions. However, I’d mention this is more of a generally #reagent question than a #re-frame specifically

ackerleytng14:06:33

actually, when i have 10 videos and i start with 5 per row

ackerleytng14:06:46

hitting - actually means that the 6th video moves the the first row

mikerod14:06:48

There are channels for both. Just in case you were not aware

ackerleytng14:06:01

i see, thanks!

mikerod14:06:08

So if video positions are going to change, don’t rely on index

mikerod14:06:18

Hopefully you can come up with a stable identifier per video to use instead

ackerleytng14:06:46

oh, you mean video #6 will just 'move' to the first row instead of being re-rendered?

mikerod14:06:04

However, if a video jumps from one component tree (a row) to another, it may not workout that that video would not re-render

mikerod14:06:17

I’d have to mess with that

mikerod14:06:29

You may have to experiment some on that front

ackerleytng14:06:11

let me try it out

ackerleytng14:06:28

when i do

(map (fn [v]
          [video-column {:key (str "v-col-" (:id v))} v]) vid-objs)
it seems like the map {:key (str "v-col-" (:id v))} is being used as the argument

ackerleytng14:06:38

to the video-column component

ackerleytng14:06:59

how should i make it such that it just provides the key?

ackerleytng14:06:15

or should i assoc it into v

mikerod14:06:16

I just add it as meta, didn’t mean to write that way

mikerod14:06:34

(map (fn [v]
          ^{:key (str "v-col-" (:id v))} [video-column  v]) vid-objs)

ackerleytng14:06:05

cool, it does improve the re-rendering performance, thanks!

ackerleytng14:06:41

also, video #6 does not just get moved to the previous row, it re-renders.

eraserhd14:06:56

Any experience here on migrating from Om.next to re-frame? Specifically, techniques for doing so gradually.

eraserhd14:06:43

Luckily, I'm not using the query routing/parse stuff.

mikerod14:06:03

@ackerleytng Yeah, I’m not sure how you could pull off having the component move to a different subtree and not re-render See below…

mikerod14:06:47

@ackerleytng this may relate to React “portals” introduced in React 16 ( I believe) https://reactjs.org/docs/portals.html

mikerod14:06:05

I haven’t used them though and am not positive. Also, haven’t considered them in conjunction with Reagent. but looks ok https://github.com/reagent-project/reagent/issues/317

ackerleytng15:06:37

think i need to understand more before i move to that

ackerleytng15:06:16

what do you think of just rendering all the videos in a column and using display: none on some of them

ackerleytng15:06:23

the video will probably get loaded only once per page load right

ackerleytng15:06:48

gotta go, thanks so much @mikerod

🎉 4
p-himik19:06:35

I have a bunch of components that interoperate with Web Audio API, so I have to sync state between my components and the API classes. I often use reagent.ratom/run! for such cases, but this time I needed to use add-watch to be able to compare a new value of a subscription to the old one. Interesting thing - when I dereference the sub after add-watch, the watch is immediately triggered with nil being the old value. It leads to all kinds of inconsistencies when not handled with the utmost care. Maybe there's some API that I'm missing? Is there something like run! (that watches for a subscription changes, has access to both new and old values, and run immediately when called) I could use instead of juggling add-watch and deref?