reagent

A minimalistic ClojureScript interface to React.js http://reagent-project.github.io/
pez 2021-03-02T11:12:12.045400Z

Hello folks. I am running into problems with reacting to the current time there is some background here https://clojurians.slack.com/archives/C073DKH9P/p1614352956019800, but will try to frame it better here. I have components that should change how they look, what they show, and what they dispatch on press (it’s react native, but I doubt that matters). The app only cares about minutes, and I want the components to react on the minute, w/o having very high requirements on performance. For this I created a ratom like so:

(defonce current-time (r/atom (t/now)))
(js/setInterval (fn []
                  (reset! current-time (t/now)))
                (* 1000 1))
And then in the components I deref it via a function that looks a bit like so:
(defn active-at? [some-time event]
  (and (t/after? @time/current-time some-time)
       (not (some #{event} [:event/foo
                            :event/bar
                            ,,,]))))
The app behaves perfectly from the looks of it! But everything is not dandy. After some minutes I get warnings like this
Warning: Please report: Excessive number of pending callbacks: 501. Some pending callbacks that might have leaked by never being called from native code: {"471":{"module":"UIManager","method":"configureNextLayoutAnimation"},"665":{"module":"UIManager","method":"configureNextLayoutAnimation"},"1192":{"module":"UIManager","method":"configureNextLayoutAnimation"},"1553":{"module":"UIManager","method":"configureNextLayoutAnimation"},"1896":{"module":"UIManager","method":"configureNextLayoutAnimation"},"1897":{"module":"UIManager","method":"configureNextLayoutAnimation"},"1923":{},"1925":{"module":"UIManager","method":"configureNextLayoutAnimation"},"1934":{"module":"UIManager","method":"configureNextLayoutAnimation"},"1936":...
I’ve tried with making the components be of form-2, but that doesn’t help. (Why it would help, I don’t know, this is a bit beyond what I currently grasp about reagent.) Anyone been down this path, or just anyway know how I should navigate? ❤️

p-himik 2021-03-02T11:19:02.047100Z

First of all, don't call js/setInterval at the top level of your NS. Make it a part of defonce, otherwise it will be called on each code reload (apologies if it works differently on React Native - I've never worked with it so I have no idea). Second of all, don't track seconds if you care only about minutes. Leave the interval to be one second, but store only minutes in current-time and call reset! when the next minute comes. I'm not sure whether that will fix the "Excessive number of pending callbacks" warning, but it's something that I definitely would've done.

pez 2021-03-02T11:21:58.048500Z

Thanks. Will do all this. (I don’t think it works differently in react native). How ever, afaiu this would make the problem 60x smaller, but it would still be there…

pez 2021-03-02T11:25:14.049Z

btw, I first had a setTimeout wrapping the setInterval where I tried to start the interVal on a minute sharp, to fire every minute, but I had some bug in that. And also thought I might get drifts from it. Your suggestion sounds like a better idea.

p-himik 2021-03-02T11:25:39.049500Z

Precursory searching shows that people have this problem because of promises. And your code with the atom doesn't use any. Are you sure this problem wasn't there before? Maybe it was simply exacerbated by the changes made every second?

2021-03-02T11:26:02.050100Z

I am guessing wildly ... but could it be that your process is being throttled in some way?? Which means there are just too many setIntervals callbacks queued up. If this guess is correct, maybe this rewrite (untested) using setTimeout will take the pressure off:

(defn reset-time
  []
  (js/setTimeout #((reset! current-time (t/now))
                   (reset-time))
    (* 1000 1)) 

(reset-time)
Ie. don't queue up another callback (via setTimeout) until the last one fired. Just a wild guess. @pez

p-himik 2021-03-02T11:26:48.050400Z

A relevant issue on GitHub with some discussion: https://github.com/facebook/react-native/issues/27483

pez 2021-03-02T11:32:40.050800Z

I haven’t even googled the problem! 🤦 . Many thanks, will check out. The problem goes away if I do not deref that atom, btw.

p-himik 2021-03-02T11:34:51.051Z

It doesn't mean that it's the atom to blame though. Derefing it in a view causes redraws whenever that atom changes. To confirm that it's not the atom, you can try queuing a redraw every second.

pez 2021-03-02T12:34:46.057700Z

Thanks, @mikethompson! ❤️ Unfortunately that didn’t do it. Maybe I’ll just hide the problem by employing @p-himik’s suggestion to use store whole minutes in the ratom. Trying it this way now:

(reg-sub
  :current-time
  (fn []
    my-time/current-time)
  (fn [t]
    t))

(reg-sub
  :current-minute-time
  :<- [:current-time]
  (fn [t _]
    (t/floor t t/minute)))
So far, no warnings. 😃 The last warning took some 4 minutes to appear so now it should take 4 hours, I think. From the SO-thread, maybe it also is only happening while the debugger is attached. Not at all sure what to do with it… There is only so much time allotted to me in this world!

pez 2021-03-02T17:08:08.061900Z

OK. So this “works” in hiding the issue. But now I have created a new issue, perhaps @p-himik called it above. When shadow-cljs reloads the code, the screen with these time components is shown (or navigated to, I am not sure yet what happens). I tried to hide the setInterval inside the defonce like so:

(defonce current-time
  (do
    (js/setInterval #(reset! current-time (t/now))
                    1000)
    (r/atom (t/now))))
The screen in questions has lots of other subscriptions and things have been dandy before…

p-himik 2021-03-02T17:09:44.062Z

From your description, I'm not sure what the issue is.

pez 2021-03-02T17:13:35.062200Z

Let me try again then. The issue is that when I save a file, the app shows the screen with components that is subscribing to the time. So the screen I am working with goes away. So it is much more like Browsersync or other JS tech behaves.

p-himik 2021-03-02T17:14:37.062500Z

Ah. To confirm: You're working on screen A. Only the screen B uses current-time. When you make any change in any file, the UI switches to the screen B. Correct?

pez 2021-03-02T17:14:55.062800Z

Exactly.

pez 2021-03-02T17:15:44.063Z

Screen B happens to be the start screen. Which might matter.

p-himik 2021-03-02T17:16:33.063200Z

It does matter. The screen A is shown because of some change you make in the whole state of the UI via navigation. That state is not stored in defonce, so it disappears because of code reload.

p-himik 2021-03-02T17:16:59.063400Z

Same as evaluating

(def a (atom nil))
(reset! a 7)
(def a (atom nil))

p-himik 2021-03-02T17:17:37.063600Z

If you're still using re-frame, then the way the current screen is determined should rely on app-db.

pez 2021-03-02T17:18:07.063800Z

So, unrelated to the current-time, thingy?

p-himik 2021-03-02T17:18:54.064Z

Unrelated.

pez 2021-03-02T17:21:43.064200Z

Indeed. Switching to where branched off I have the same behaviour. Thanks!

1👍
Aaron Decker 2021-03-02T19:23:05.064900Z

Does anyone have impressions to share on drag'n'drop libraries that have worked for you in your Reagent apps? It looks like my main options are https://github.com/react-dnd/react-dnd or going cljs-native with https://github.com/Kah0ona/re-dnd but I wanted to see if the community had any recommendations.

rberger 2021-03-07T02:39:29.078300Z

We were able to use https://github.com/atlassian/react-beautiful-dnd in our reagent/re-frame app. But it (and DnD in general) were the hardest for me to get my mind around to get into reagent / JS interop. Have a very simple literal translation from a JS example to a CLJS / Reagent in https://github.com/omnyway-labs/simple-list-dnd We since made a more Clojurescript / reagent style implementation but its kind of embedded in our app for now

2021-03-02T19:49:08.069300Z

I am having some fun time with mui component and it’s inputs and got stuck a bit. Basically, I am trying to use https://material-ui-pickers.dev/api/KeyboardDatePicker and following [this](https://github.com/reagent-project/reagent/blob/master/doc/examples/material-ui.md) example I managed to get the input somewhat working, but it still doesn’t feel quite right. This is what I got now:

[mui/keyboard-date-picker
 {:variant   :inline
  :format    "dd/MM/yyyy"
  :InputProps {:inputComponent mui/input-component}
  :value     (values :date)
  :on-blur   handle-blur
  :on-change (fn [event _]
               (set-values {:date event}))}]
But when I input the date it goes something like 10/10/0002, when I type 10/10/2. Basically, I am not sure on the direction I can take now so I would really appreciate any suggestions.

p-himik 2021-03-02T19:53:10.069600Z

I don't know for sure, but seems like :on-change is called either on every keystroke or on every input that it can possibly parse. If so, you could check in :on-change whether the string is complete and only then call set-values.

2021-03-02T19:54:06.069800Z

it’s basically nil until it’s fully set

2021-03-02T19:55:22.070Z

actually I’m wrong

2021-03-02T19:55:29.070200Z

okay thanks, I think I got it

2021-03-02T19:58:38.070400Z

re-wrote on-change with

:on-change (fn [event text]
  (prn :text text)
  (when-not (and (string? text)
                 (re-find #"\_" text))
    (set-values {:date event})))
works like a charm :partywombat:

1👍