reagent

A minimalistic ClojureScript interface to React.js http://reagent-project.github.io/
frozar 2020-03-13T11:03:49.144900Z

Hi, does anyone use the last version of reagent 0.10.0 ? Because after this update on my tiny project, I realised that the function http://reagent.com/render doesn't do the job anymore. In the result page, the tag "app" is empty, and I wonder if I miss something... I also change the require in the beginning of my file obviously (:require [reagent.dom :as reagent])

jplaza 2020-03-13T11:23:13.145900Z

Hi! I just created a demo project with the default lein template and changed the version to 0.10.0 and it’s working

2020-03-13T12:20:30.146Z

you could use it like this :

(require [reagent.core :as r]
[reagent.dom :as rd])
(rd/render ...)

2020-03-13T12:21:35.146300Z

reagent .core is always needed

frozar 2020-03-13T13:39:10.146500Z

Thank you for the rely. Even with these indications I experience the same issue with the render function...

frozar 2020-03-13T13:40:36.147800Z

Thank for the effort @jplaza,as I still experiment issue with render function, I will create a small shadow-cljs based example to check this out.

2020-03-13T13:47:36.147900Z

do you have some code ?

frozar 2020-03-13T13:48:28.148100Z

Yes, I have, the time I make a commit and I send it to you 😉

frozar 2020-03-13T13:50:33.149Z

I made a basic example of reagent with shadow-cljs and the render function works well 🙂

jplaza 2020-03-13T13:52:57.149200Z

:thumbsup:

frozar 2020-03-13T13:57:39.149300Z

I'm generating svg hiccup node in my project, and after a quick test, I think that my code is slightly buggy. I have to check it. By the way my project is : https://github.com/frozar/roughcljs The buggy code is not commited on the repo, not yet at least

frozar 2020-03-13T14:20:06.149600Z

Ok, it was a silly mistake in my code. I just learn there is a difference between using '(...) or (list ...) 🙃

frozar 2020-03-13T14:29:00.149800Z

Also the namespace reagent.core is not required to make the render function works. The namespace reagent.dom is enough 😉

2020-03-13T14:45:52.150Z

oups 🙂

2020-03-13T14:45:58.150200Z

thzanks

worlds-endless 2020-03-13T15:23:33.151200Z

Does anyone have a working "confirm you want to leave the page?" solution in Reagent or re-frame for when they are leaving (link or back-button) a page that has data on it?

p-himik 2020-03-13T15:28:07.151300Z

It's trivial - just start listening to the beforeunload event when there's data and stop listening to it when there's no data.

worlds-endless 2020-03-13T16:51:52.151500Z

I'm not familiar with "stop listening" in js. I take it it doesn'tm atter much where you put this js?

p-himik 2020-03-13T16:54:10.151700Z

Regarding "stop listening": https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener

👍 1
p-himik 2020-03-13T16:55:08.152200Z

It matters when that code is executed. Where it physically ends up in the JS bundle doesn't matter.

mbarillier 2020-03-13T18:26:06.155900Z

seeing weirdness on safari with reagent/re-frame + bootstrap:

[:select.form-control {:on-click #(js/alert "clicked")} ...items...]
works on linux chrome and firefox but doesn't work on safari. (this is just a debugging on-click handler, the real one gets the id and does something useful.) is there a known issue with bootstrap/react/reagent on mac?

p-himik 2020-03-13T18:27:21.156Z

Just a guess, and probably based on some outdated knowledge - try replacing #(js/alert ...) with (fn [] (js/alert ...) nil).

mbarillier 2020-03-13T18:30:05.156200Z

unfortunately, nope: didn't work. :)

p-himik 2020-03-13T18:32:06.156400Z

The next guess is that WebKit browsers just don't like having :on-click on :select. Dunno.

otwieracz 2020-03-13T20:07:02.156800Z

I am trying to create formatter component for React Data Grid in Reagent: https://adazzle.github.io/react-data-grid/docs/examples/cell-formatting

otwieracz 2020-03-13T20:08:09.157700Z

Each of my columns definition looks like: ^{:key id} {:key id :name text :editable true :formatter formatter}) and I thought that simple (defn formatter [data] (str (.-value data))) will be enough

otwieracz 2020-03-13T20:08:32.158Z

Howver, trying to use any formatter produces error: react-dom.development.js:13436 Uncaught Error: Objects are not valid as a React child (found: object with keys {key, val, __hash, cljs$lang$protocol_mask$partition0$, cljs$lang$protocol_mask$partition1$}). If you meant to render a collection of children, use an array instead.

p-himik 2020-03-13T20:20:03.158300Z

Can you provide the rest of the code that instantiates ReactDataGrid?

otwieracz 2020-03-13T20:23:29.158500Z

Sure:

otwieracz 2020-03-13T20:23:30.158700Z

(defn formatter [data]
  [:div (str (.-value data))])

(defn- columns
  [notes tags]
  (let [number-of-columns (reduce max (map (comp count #(:note/objects %)) notes))
        columns-tags-list (columns-tags notes tags)
        column-names (seq-overlay (range 0 number-of-columns)
                                  (map #(string/join ", " %)
                                       columns-tags-list))]
    (map (fn [id text]
           ^{:key id} {:key id :name text :editable true :formatter formatter})
         (range))
    column-names))

(defn- row-getter
  [notes i]
  (when (>= i 0)
    (->> (nth notes i)
         (:note/objects)
         (zipmap (range)))))


(defn index []
  (let [notes @(rf/subscribe [:notes/notes])
        tags @(rf/subscribe [:tags/tags])]
    [:> ReactDataGrid
     {:columns (columns notes tags)
      :rowGetter (partial row-getter notes)
      :rowsCount (count notes)
      :enableCellSelect true}]))

otwieracz 2020-03-13T20:23:39.158900Z

That's everything that's important.

p-himik 2020-03-13T20:38:03.159100Z

Your columns function just returns column-names.

p-himik 2020-03-13T20:39:31.159300Z

Also, your row-getter returns a map of integers to the elements in :note/objects for each row. But ReactDataGrid expects it to be a JS object.

p-himik 2020-03-13T20:40:12.159500Z

(TBH, I don't recall if Reagent converts props from CLJS to JS recursively for :> components)

p-himik 2020-03-13T20:40:32.159700Z

Also, you don't need ^{:key id} in there since what you return is not a React child.

p-himik 2020-03-13T20:42:15.159900Z

Start with the smallest JS example possible and convert it to CLJS as is, without anything advanced. Then, gradually make it more "CLJS-ey", while making sure that it still works.

otwieracz 2020-03-13T20:43:44.160100Z

wait, wait

otwieracz 2020-03-13T20:44:03.160300Z

Everything works fine if only I remove :formatter formatter from column map.

otwieracz 2020-03-13T20:44:07.160500Z

Fomratter is the issue here.

otwieracz 2020-03-13T20:45:48.160800Z

I just noticed that I made a mistake in this paste. There was :formatter true where it should be :formatter formatter.

mbarillier 2020-03-13T20:50:45.161300Z

second guess was correct: I changed :on-click to :on-change and it works on linux+mac/chrome+safari+firefox. thanks!

otwieracz 2020-03-13T20:53:49.161500Z

Ok - sorry for bad examples.

otwieracz 2020-03-13T20:55:45.161700Z

(defn formatter [data]
  (let [props (.-value data)]
    [:div (str props)]))

(defn- columns
  [notes tags]
  (let [number-of-columns (reduce max (map (comp count #(:note/objects %)) notes))
        columns-tags-list (columns-tags notes tags)
        column-names (seq-overlay (range 0 number-of-columns)
                                  (map #(string/join ", " %)
                                       columns-tags-list))]
    (map (fn [id text]
           {:key id :name text :editable true #_#_:formatter formatter})
         (range)
         column-names)))

(defn- row-getter
  [notes i]
  (when (>= i 0)
    (->> (nth notes i)
         (:note/objects)
         (map str)
         (zipmap (range)))))


(defn index []
  (let [notes @(rf/subscribe [:notes/notes])
        tags @(rf/subscribe [:tags/tags])]
    [:> ReactDataGrid
     {:columns (columns notes tags)
      :rowGetter (partial row-getter notes)
      :rowsCount (count notes)
      :enableCellSelect true}]))
this works fine, while this:
(defn formatter [_data]
  [:div "foo"])

(defn- columns
  [notes tags]
  (let [number-of-columns (reduce max (map (comp count #(:note/objects %)) notes))
        columns-tags-list (columns-tags notes tags)
        column-names (seq-overlay (range 0 number-of-columns)
                                  (map #(string/join ", " %)
                                       columns-tags-list))]
    (map (fn [id text]
           {:key id :name text :editable true :formatter formatter})
         (range)
         column-names)))
fails with:

p-himik 2020-03-13T21:07:45.162100Z

OK, so you also fixed the columns returning just column-names. :) What you see is caused by the fact that :formatter is expected to be a function that returns a React component. But you provide it a function that returns a CLJS vector. Read this: https://github.com/reagent-project/reagent/blob/master/doc/InteropWithReact.md#creating-react-components-from-reagent-components

p-himik 2020-03-13T21:16:38.162400Z

Ah, I see, you also want to handle situations when the HTML5 history is changed. It's this event: https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event But I don't think you can cancel it. And even if you could, it would not be robust. E.g. consider this function:

(defn set-page [page-id]
  (reset! current-page page-id)
  (set-html5-history-state (get-page-url page-id)))
With this example, even if you were able to cancel the event, the current-page would now be in an inconsistent state. A robust approach is to do it at your application's level and not with JS events.

otwieracz 2020-03-13T21:18:51.162700Z

Thank you! I've expected something like that 🙂

otwieracz 2020-03-13T21:25:55.162900Z

Hmm, but somehow :value in props end up as string..

otwieracz 2020-03-13T21:26:09.163100Z

ok wait

otwieracz 2020-03-13T21:26:11.163300Z

my fault!

otwieracz 2020-03-13T21:26:39.163500Z

And everything is working. Thank you very, very much!

👍 1