Fork me on GitHub
#reagent
<
2018-05-25
>
theeternalpulse00:05:48

Is there a way to provide a context like mechanism so that you can do something like

(defn nested-component
  ^{:context [:state]}
  [v state]
  [:div
   [:span v]
   [:span (:a @state)]])

(defn child-component
  []
  [nested-component 1])

(defn main-with-context
  ^{:state (r/atom {:a 1 :b 2})}
  []
  [child-component])

theeternalpulse00:05:35

even a way to hook in a function that gets called whenever a component's children are rendered that aren't html elements

athomasoriginal01:05:06

Is context not supported in latest reagent?

theeternalpulse01:05:32

Should have looked, but there are plugins. I like my syntax but I guess this is probably easier to do. https://github.com/Lokeh/reagent-context

theeternalpulse01:05:29

it has a pretty nasty gotcha I think, requiring more compensation to "get at" the re-rendering..

theeternalpulse14:05:10

I have not, looks simple and easy to wrap for the time being.

troglotit14:05:04

Did anyone has issue with soda-ash inputs, that cursor jumps to the end of input while editing? As I google, it seems it’s common pain-point. I got why it’s like this 🙁

troglotit14:05:07

Did anyone integrate reagent’s cursor reposition into their own components? I’d want to see examples 🙂

achikin15:05:19

Is reagent smart enough to detect that component has changed from form-1 to form-2?

troglotit15:05:35

I’m pretty sure it shouldn’t detect it. But maybe it will after full re-mount of component. nvm 😅 , imo it should just break

achikin15:05:40

I've tried it and it works when you change from form 1 to form 2, but not the other way around.

achikin15:05:17

The use case is the following

achikin15:05:19

So, I render a view which shows some data from subscription, but the data is not in app-db at that moment, so the subscription returns nil. In that case I don't want to render my view, because it captures data in an atom in closure, so I render some dumb div instead. But when data finally arrives to app-db - I render the view as a proper form 2 component.

achikin15:05:50

I already know that in this case reagent is able to switch from from 1 to form 2. My question is how reliable is that?

quangh16:05:57

@deadghost did you have any luck with rc-slider?

justinlee16:05:46

@achikin totally reliable. the render function checks the return type each time: if it’s a vector, then its a form-1. if it’s another function, then its a form-2

😀 4
justinlee16:05:18

oh but that’s not what you’re asking, sorry

justinlee16:05:05

right interesting. i think you are right that once you’ve rendered a form-2 component, you’re not going to get back to the form-1 component

justinlee16:05:09

i’d want to check that

justinlee16:05:56

but based on my review of the source code, I think that the outer conditional won’t be reevaluated on subsequent renders once you’ve installed the inner render function

pesterhazy17:05:41

I had an issue this week that was probably related to switching between Form-2 and Form-1. It took me a few hours to fix

pesterhazy17:05:07

My assumption was that you can freely switch but apparently that’s not the case

justinlee17:05:50

the whole point of form-2 is that it only evals the outer form once. all subsequent evals are only of the inner function

pesterhazy17:05:52

The symptom was that the component didn’t rerender reliably

justinlee17:05:06

if it re-evaluated the outer form, then you’d lose local state

justinlee17:05:55

right. so with this code:

(defn swapper
  [inner]
  (spy inner)
  (if inner (fn [inner] [:div "SOMETHING"])
            [:div "NOTHING"]))

(defn test-component []
  (let [outer (reagent/atom false)]
    (fn []
      [:div {:on-click (fn [] (spy outer) (swap! outer not))}
       [swapper @outer]])))

justinlee17:05:16

it renders “NOTHING” first, then when you click on it, it renders “SOMETHING” forever

justinlee17:05:58

The console shows that the outer value is changing and that the outer form in swapper is never reevaluated once the render func is installed:

seekeasy.core:96: inner: false
seekeasy.core:103: outer: #<Atom: false>
seekeasy.core:96: inner: true
seekeasy.core:103: outer: #<Atom: true>
seekeasy.core:103: outer: #<Atom: false>
seekeasy.core:103: outer: #<Atom: true>

achikin17:05:00

right. I got exactly the same result/

pesterhazy17:05:22

It makes sense the way you describe it

pesterhazy17:05:33

But it wasn’t clear to me before

pesterhazy17:05:41

This is a real gotcha

pesterhazy17:05:11

Another “rookie mistake” to add to the docs?

justinlee17:05:22

probably yes

justinlee17:05:33

you know, most of the unexpected stuff happens with form-2 components

pesterhazy17:05:04

As opposed to Form-3?

justinlee17:05:16

right. the only real gotcha with form-3 (other than all of the normal react gotchas) is getting the render function named correctly and remembering to repeat parameters

justinlee17:05:51

well maybe that’s not right. i don’t know

justinlee18:05:09

i like reagent but i have this nagging feeling like there is too much magic and not enough assistance

justinlee18:05:28

i really dislike libraries where the only way to use them is to understand the implementation

kurt-o-sys18:05:38

I'm trying to use react-select (https://github.com/JedWatson/react-select) in a react-bootstrap-table. I've got this:

(reagent/as-element
     (let [state (reagent/atom ["val"])]
       [:> Select {:multi    true
                   :value    @state
                   :onChange (fn [new-vals]
                               (js/console.log new-vals)
                               (reset! state new-vals)
                               (js/console.log @state))
                   :options  [{:label "whatever"
                               :value "val"}
                              {:label "whatever - 2"
                               :value "someval"} ]}]))
But if I update the state in the onChange function, the state doesn't seem to be updated and the component not rerendered... What am I missing?

gadfly36118:05:59

@kurt-o-sys Just looking at the code snippet (and not the context of react-select or react-bootstrap-table), I'd have written it like this:

gadfly36118:05:14

(defn foobar []
  (let [state (reagent/atom ["val"])]
    (fn []
      [:> Select
       {:multi    true
        :value    @state
        :onChange (fn [new-vals]
                    (js/console.log new-vals)
                    (reset! state new-vals)
                    (js/console.log @state))
        :options  [{:label "whatever"
                    :value "val"}
                   {:label "whatever - 2"
                    :value "someval"} ]}])))

gadfly36118:05:05

Also, where is Select coming from? Did you create a var above that grabbed it from the js/ namespace?

kurt-o-sys18:05:40

Right... that's what I thought, but I can't seem to add this as a 'component' to react-bootstrap table. - Oh, I got that Select from "react-select" :default Select] (shadow-cljs syntax). That works.

kurt-o-sys18:05:10

So, if I turn it into that function you show, than I get an error, sec...

gadfly36118:05:45

to say it another way, the code as you wrote it above, won't persist the state reagent atom between rerenders

justinlee18:05:47

@kurt-o-sys the way you’ve written it, the atom will be reinitialized on every render. that’s why @gadfly361 wrapped in in a form-2

👍 4
kurt-o-sys18:05:35

OK, makes sense... so that's why I need that function, right? But in that case, when I add it to another React component that expects a child component: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.

kurt-o-sys18:05:37

(that's why I added that reagent/as-element)

justinlee18:05:41

you’ll have to use it like this: (reagent/as-element [foobar])

kurt-o-sys18:05:55

oh, ok... let me try 🙂

justinlee18:05:39

foobar is indeed just a function, which is okay when using it with reagent. but if you pass it to a react function you’ve got to manually call as-element to turn it into a react element

👍 4
kurt-o-sys18:05:42

ok, I start to get it... works, thx a lot!

bubblebobble 8
Bravi19:05:48

can anyone recommend a good date-picker component I could use in my project?

Bravi19:05:16

@gadfly361 do you happen to have an example of how to use it? I’ve added the required dependencies, but still nothing shows up unfortunately

gadfly36120:05:08

@bravilogy out for a bit, but I can get back to you with a snippet

Bravi20:05:20

ah thanks, that’d be very helpful

crinklywrappr21:05:44

IOW [:> popup {:trigger ???}]

justinlee21:05:46

@doubleagent I think [:> popup {:trigger (reagent/as-element [:> Button {:icon "add"}])}]

gadfly36121:05:41

@lee.justin.m beat me to it, what he said :)

crinklywrappr21:05:52

🙂 thanks guys!

Bravi21:05:14

hey guys, how can I do this in cljs?

import 'react-dates/initialize';

Bravi21:05:31

that’s js btw

Bravi21:05:02

As such, you need to import react-dates/initialize to set up class names on our components. This import should go at the top of your application as you won't be able to import any react-dates components without it.

Bravi21:05:07

from docs

Bravi21:05:36

I’ve imported the library, but components are not accessible or something. basically I can’t use them without that bit of code

justinlee21:05:19

@bravilogy with shadow-cljs you can just do a (:require ["react-dates/initialize" :as init])

justinlee21:05:43

with the normal compiler I suspect you have to create an alias using foreign-libs or something

Bravi21:05:51

ah damn it 😄 using lein here. is it too difficult to convert to shadow-cljs? just looking at the docs now

justinlee21:05:49

well if you’ve already imported the main library then just do whatever you with that to import the submodule

justinlee21:05:07

if you are doing a lot of npm stuff, shadow-cljs makes it a hell of a lot easier

gadfly36121:05:49

@bravilogy answering your earlier question for an example with react-dates (note, this is untested and based on leiningen instead of shadow-cljs). 1. lein new reagent-figwheel rd 2. Add [cljsjs/react-dates "12.2.4-1"] to :dependencies vector in project.clj 3. Open src/rd/core.cljs and add the following to the namespace :require

[cljsjs.react-dates]
[goog.object :as gobj]
4. Replace the Page section with the following:
(def date-range-picker
  (reagent/adapt-react-class
   (gobj/get js/ReactDates "DateRangePicker")))


(defn page [ratom]
  [:div
   [date-range-picker
    {
     ;; Add date range options here
     }]
   ])
5. In a terminal run, lein figwheel dev and navigate to http://localhost:3449

Bravi21:05:09

@gadfly361 thanks, I tried it that way before, but without using reagent/adapt-react-class. I used

[:> js/ReactDates.SingleDatePicker ..]
and it was firing events, but wasn’t showing anything. now I’ve tried it with adapt-react-class and I’m getting errors like
Failed prop type: The prop `onDateChange` is marked as required in `SingleDatePicker`, but its value is undefined.
And I’m using it like so
[:div.form-group.row
              [single-date-picker (clj->js {:on-focus-change #(js/console.log "hello")
                                           :on-date-change #(js/console.log "hey")})]

Bravi21:05:45

and it’s the same without clj->js too. let me just do lein clean and reload. maybe there’s something caching

Bravi21:05:21

ok now it’s the same thing - events are being fired and there’s nothing showing up. I’m pretty sure it’s because of css

gadfly36121:05:57

@bravilogy yeah, there is a css file you'd need to include in your index.html file

gadfly36121:05:30

@bravilogy try adding this ☝️