Fork me on GitHub
#reagent
<
2018-02-07
>
jmromrell17:02:49

Cross-posting from #clojurescript, I am having a hard time figuring out how to pass components as arguments to another component

jmromrell17:02:31

I am trying to create a "tree" of nested reagent components, each node has a content component passed to it, as well as any number of child component nodes

jmromrell17:02:39

This is what I have arrived at so far:

jmromrell17:02:42

(defn simple-node [node-content & children]
  (let [node-state (r/atom {})]
    (fn [node-content & children]
      [:li.tree-node
       [:div.tree-content node-content]
       [:ul.tree-body
        (map-indexed #(with-meta %2 {:key %1}) children)]])))

jmromrell17:02:12

This works, except that when I update a session value referenced by one node's node-content, all nodes re-render

jmromrell17:02:37

Demonstrated by the following code:

jmromrell17:02:39

[:div
   [:div (labelled-input :string "A" [:a])]
   [:div (labelled-input :string "B" [:b])]
   [:div (labelled-input :string "C" [:c])]
   [simple-node [:p (str (session/get :a) " " (rand-int 10000))]
    [simple-node [:p (str (session/get :b) " " (rand-int 10000))]
     [simple-node [:p (str (session/get :c) " " (rand-int 10000))]]]]]

jmromrell17:02:10

(labelled-input is just an HTML string input, allowing me to modify the session values)

justinlee17:02:58

when you say “session value” you mean when you update the “note-state” atom?

jmromrell17:02:30

I am updating a value in the reagent session atom

jmromrell17:02:00

Referenced by the node-contents passed in.

jmromrell17:02:24

node-state is unused for now. It is only there because I eventually wish each node to maintain its own state (whether it is collapsed or expanded, for example)

justinlee17:02:10

okay i’m not an expert but I think that’s as expected.

justinlee17:02:27

if you update any part of an atom, then anything that references any part of the atom will get updated

justinlee17:02:34

if you want to isolate, i think you have to use a cursor

jmromrell17:02:52

The reagent session namespace includes functions that use cursors under the hood

jmromrell17:02:01

(session/get :a) makes use of a cursor, in my above code

justinlee17:02:15

oh okay, sorry. i haven’t used it before. let me look to see what else could be causing it.

jmromrell17:02:59

If I don't make use of the simple-node function, and instead just have the three content components at the top level, they will only re-render when I change their referenced value

justinlee17:02:57

does updating session :c make the parent nodes re-render or is it just the parent causing the children to rerender?

jmromrell17:02:22

All nodes re-render regardless of which value (a, b, or c) I update

jmromrell17:02:20

Actually, I think I just got it working

jmromrell17:02:39

I needed to change my use case like so

jmromrell17:02:46

(defn node-content [path]
  [:p (str (session/get-in path) " " (rand-int 10000))])

jmromrell17:02:53

[simple-node [node-content [:a]]
    [simple-node [node-content [:b]]
     [simple-node [node-content [:c]]]]]

jmromrell17:02:19

For some reason, the in-lined 'content' components were not rendering as if they were their own components

jmromrell17:02:40

Until I made it explicit by defining them as their own function

jmromrell17:02:47

Thanks for the help 🙂

justinlee17:02:30

ohhh right. when you did it the original way, the function calls referencing the session were happening in the render function of whatever was producing that top-level div

justinlee17:02:58

so the top-level component was watching everything.

jmromrell17:02:30

That makes sense

justinlee17:02:19

the thing that perpetually confuses me with reagent is that () and [] look very similar but they just don’t evaluate at the same time

jmromrell17:02:08

Yeah, I'm still getting used to it. Just realized last weekend that we have been using reagent all wrong for months lol

jmromrell17:02:38

None of the devs on my team are particularly keen to work on front-end, and only used reagent because it came built-in with the luminus template

justinlee17:02:25

i feel like there were three hard lessons: atoms vs. cursors, form1 vs form2, and () vs []. once i figured that out, i really like it. but it is yet another library where i think it would be easier to understand if the docs explained what the library is doing under the hood rather than just trying to explain how to use it.

eoliphant17:02:18

Is it possible to render html comments from hiccup/reagent?

justinlee17:02:36

@eoliphant A quick search suggests that in react the only way to do it is to manipulate the dom directly after mount. https://stackoverflow.com/questions/40015336/how-to-render-a-html-comment-in-react/41131326#41131326 You obviously can replicate this technique in reagent. Whether there is a more direct way I don’t know.

eoliphant18:02:46

Ok, yeah I’d pokedaround some. Was hoping there was something simple lol

mynomoto19:02:03

mjmeintjes on #shadow-cljs mentioned that > Using the components is then simple, just use the special :> operator reagent provides, for example [:> Card {} ] Is there some docs about :>? Seems very useful.

eoliphant20:02:00

It’s pretty straightforward. If you have a reference to the React object you just use it directly.

justinlee20:02:18

what’s crazy about it is that i just cloned the entire reagent repository and grepped for it in the code. the only place it exists is (1) docs (2) tests (3) comments

justinlee20:02:21

there’s a file that suggests it is just a synonym for adapt-react-class

justinlee20:02:35

it’s just bonkers that it doesn’t appear in the api docs and i can’t find its implementation

eoliphant20:02:56

as an example @mynomoto I have some code that uses the cljsjs packaged version of react-datepicker

...
(:require [cljsjs.react-datepicker] ...
; exposes js/DatePicker so you can..
[:> js/DatePicker {opts...}]
I prefer using adapt-react-class as it makes the component usage native reagent with no need for the special syntax

justinlee20:02:09

for what it is worth, the only documentation I can find is here (you’ll have to search for it because it is towards the bottom of the page) http://reagent-project.github.io/news/news060-alpha.html