Fork me on GitHub
#reagent
<
2018-06-01
>
idiomancy00:06:48

can someone tell me why this does work? I am using a calling a form-2 component as a function rather than passing it in as a vector, and I'm having a hard time reasoning about what this actually does or means:

idiomancy00:06:06

My hypothesis was that this would cause MAIN PANEL RERENDER to be logged each time the interval fired, because I was embedding the function directly into the parent component.... instead, EXAMPLE COMPONENT RERENDER is being logged every second

idiomancy00:06:09

So, I guess what this means is that the inner function of example-component is being returned by the function call and it is being embedded into the main-panel as a.... a what? a form-1 component?

justinlee01:06:41

@idiomancy so a form-2 component is any function that returns a function on its first evaluation

justinlee01:06:29

here, the MAIN log gets evaluated, then the inner let gets evaluated, then the inner function is returned, closing over the let

justinlee01:06:51

then reagent runs the inner function in a reaction

justinlee01:06:46

It is basically the same code as this as far as reagent is concerned:

(defn test-component []
  (js/console.log "MAIN PANEL RERENDER")
  (let [s (reagent/atom 0)]
    (js/setInterval #(swap! s inc) 1000)
    (fn []
      (js/console.log "EXAMPLE COMPONENT RERENDER")
      [:div @s])))

idiomancy01:06:47

so, what, then, is react/reagent doing if I instead use [example-component] in the main panel vs putting (example-component) which I am doing in my example?

justinlee01:06:32

so in that case, main-panel is evaluated and returns a vector. the example-component is run later

justinlee01:06:46

reagent sees that you intend to create a component, and it makes one

idiomancy01:06:33

so in the first example, where a function was returned in-line, no component was inferred?

justinlee01:06:57

I, personally, kept getting quite confused about what reagent was doing because to me [example-component] looked like a “special” kind of function invocation, but it isn’t. it’s just creating plain data, which reagent later interprets.

justinlee01:06:06

correct: no brackets, no component

idiomancy01:06:58

hmm. so, the thing is, my understanding was that since no component was created, the main panel would be rerendered every time that atom was derefed in that function

justinlee01:06:13

what reagent is doing is actually quite complicated and subtle: it is effectively adding another virtual layer of clojurescript data on top of the react virtual dom system.

idiomancy01:06:34

since it was effectively being deref'd in the main panel component, no?

justinlee01:06:50

except that think about when the deref happens: it happens during the invocation of the anonymous function

justinlee01:06:36

compare with this:

(defn example-component []
  (let [s (reagent/atom 0)]
    @s
    (js/setInterval #(swap! s inc) 1000)
    (fn []
      (js/console.log "EXAMPLE COMPONENT RERENDER")
      [:div @s])))

justinlee01:06:50

if you did that, it would be different

idiomancy01:06:07

okay, so the reagent atom does not associate the deref with the component where the function lives?

justinlee01:06:28

oh wait actually it’s not dong what i expecte

idiomancy01:06:32

I wish there was some kind of "component-expand" macro that I could use to see a bit more about the data it is constructing

justinlee01:06:43

I would have expected a deref in example-component to cause a re-render. But I guess reagent doesn’t actually track derefs in form-2 components

justinlee01:06:54

that would make sense I suppose because it would always be broken

justinlee01:06:03

you would always reset your local state

idiomancy01:06:48

Really? I thought it did track derefs in form-2 components

idiomancy01:06:06

so you're saying only a change in args causes form-2 components to rerender?

justinlee01:06:26

reagent doesn’t know “where” textually the atom is. it isn’t doing lexical analysis. what it does is keep track of every atom or cursor you deref during the running of the render function

justinlee01:06:48

the thing I was confused about is that the “render” function in a form-2 component is the inner function, not the outer function

idiomancy01:06:33

hahaha, yeah, I sure hope its not using textual analysis. I was assuming some other black magic was going on, since I'm not even sure how it does its tracking to begin with. Like theoretically it could be adding components seen to a stack, and assuming that when it sees a deref, the last component in the stack was the owner of that deref, which would then mean it would still associate anonymous function derefs with the component its contained in.

idiomancy01:06:48

but I mean, I assume that would be a stupid implementation

idiomancy01:06:54

but hell if I know what that thing is doing

justinlee01:06:28

reagent sets a dynamically scoped variable before the render function starts and then the implementation of the deref function in the reagent/atom keeps track of what is currently running based on that variable

idiomancy01:06:24

okay, that's super helpful

idiomancy01:06:39

thank you, my friend!

justinlee01:06:29

It’s this piece of code that does all the magic if you are curious https://github.com/reagent-project/reagent/blob/master/src/reagent/ratom.cljs#L51-L56

🔥 4
mikethompson01:06:04

@idiomancy also be sure to read the /docs. Much of this discussion is covered in there.

idiomancy01:06:39

by /docs, you mean the /doc subdirectory on the reagent github, right?

idiomancy01:06:11

okay, cool. Thanks! Sorry for failing to rtfm 😅

idiomancy01:06:20

> But, eventually, you'll want to understand how that magic happens. Otherwise ... one day, in the peace of a shower, or on that serene bike ride to work, your eyes will flick to the left and you'll wonder "wait, how exactly has this EVER worked for me all this time?". Which can be followed by other doubts: "if I don't understand this, what else don't I know?", which can lead to "do I really understand ANYTHING?". And, before you know it, you'll be over at your parent's house demanding to know if you were adopted. They get me.

mikethompson01:06:37

Yeah, i wrote that :-)

mikethompson01:06:41

Once you get through tutorials 2, 3, 4, you'll be well on your way.

idiomancy01:06:13

Excellent. Thanks for all your hard work!

👍 4
oliy10:06:05

Possibly a noob question, but we are currently using reagent 0.7.0 with react-with-addons 15.6.1-0. to upgrade to reagent 0.8.1 we should upgrade to react-with-addons 16.3.2-0 but it doesn't exist on cljsjs. Is react-with-addons still a thing?

pesterhazy10:06:01

i think the addons are frozen at 15.something but they should still work

pesterhazy10:06:35

AFAIK they're not actively developed anymore by the React team

oliy10:06:06

We currently exclude react from the reagent deps and use react-with-addons instead, would rather stay on the version reagent is developed against, so something will have to change. I'll dig a bit further, thanks for your help @pesterhazy

folcon11:06:25

Hey everyone, are there any good resources for covering js interop in the context of components? I keep picking things up piecemeal regarding this and can’t help but think that going over something more comprehensive would be helpful!

troglotit11:06:08

I think https://github.com/reagent-project/reagent/blob/master/doc/InteropWithReact.md should cover everything. If something is not clear after that document, I think we should add changes to it.

folcon11:06:30

Hmm, ok. I’ll start there. 😃

vinai14:06:51

I need to delegate autoplay permissions to a cross-origin iframe. According to http://developers.google.com that can be done by adding the attribute allow="autoplay; fullscreen" to the iframe element. I am able to allow full screen by using the :allow-full-screen true props, but I can't use :allow-autoplay, :allow-auto-play or :allow "autoplay" without react complaining about an invalid attribute. Is there a way to force the attribute to be rendered without a warning?

mikerod14:06:37

@vinai I think this may be a past version of React issue

mikerod14:06:41

What version are you using?

vinai14:06:52

oh? Good call, let me check...

vinai14:06:16

cljsjs/react-dom "15.6.1-2"

mikerod14:06:44

Pre React 16 didn’t allow unknown attributes to make it through to the DOM

mikerod14:06:36

I think the workarounds were ugly hacks around using JavaScript to grab the actual DOM element after it was created and add the attributes via the DOM/JS interface

vinai14:06:58

Thanks, I'll try upgrading...

mikerod14:06:17

I am not a good example here, I still haven’t upgraded, but it does seem that Reagent has supported React 16 for some time. I have only ran into this non-custom-attribute thing once before and eventually just found a workaroudn where I didn’t need it. I’d probably encourage upgrading. I should as well.

mikerod14:06:56

For fun, you can see how it is worked around in https://github.com/facebook/react/issues/140#issuecomment-65161467 (but you’d have to translate to the Reagent equivalents)

vinai14:06:12

It would be nice to be able to avoid injecting the attribute with js 🙂

vinai14:06:24

Thanks for the help

mikerod14:06:32

No problem

vinai14:06:11

So far so good. On first glance nothing is broken and I'm able to use the allow attribute 🎉 Still might run into issues later though

mikerod14:06:28

I think it is supposed to typically be a fairly smoother upgrade

justinlee18:06:50

i only ask because lots of people miss this doc

👍 4
jonjonray18:06:19

I have and I tried doing it like I would a typical prop in reagent, but it doesn't seem to work

justinlee18:06:00

you should just be able to pass your props as a map for the first argument

jonjonray18:06:00

so for example doing [react-tooltip {:type "light"}] actually breaks the component

justinlee18:06:05

what does it do?

jonjonray18:06:12

let me recreate and I'll send the error

jonjonray18:06:29

so it somehow works now

jonjonray18:06:39

Please disregard my previous question 😂

justinlee18:06:01

well alls well that ends well