re-frame

https://github.com/Day8/re-frame/blob/master/docs/README.md https://github.com/Day8/re-frame/blob/master/docs/External-Resources.md
zackteo 2021-06-23T02:04:11.214400Z

Hi I have an event like so

(rf/reg-event-fx
  :map/swap-results
  (fn [{:keys [db]} [_ results]]
    {:dispatch-n [[:map/remove-results]
                  [:map/add-results results]]}))
For react component reasons, I need to remove results before adding them. This sends the 2 events in order but it seems like there is not to render the map after :map/remove-results is there a way to wait for awhile before the :map/add-results event?

p-himik 2021-06-23T09:03:30.225900Z

There is: https://github.com/day8/re-frame/blob/master/docs/Solve-the-CPU-hog-problem.md#forcing-a-one-off-render But I would definitely not use it here simply because you're changing your re-frame workflow to, as far as I understand, work around some React component issues. Instead of doing that, create a thin Reagent wrapper around that component and work around that problem there. It will become much simpler in the end, much easier to reason about, and easier to reuse.

zackteo 2021-06-23T02:20:10.216Z

For now my workaround is to have a button dispatching map/remove-results to clear the map, then click the result that dispatches map/add-result to display the geojson on the map

emccue 2021-06-23T03:15:37.216400Z

might sound dumb, but track the requests in your state

emccue 2021-06-23T03:16:18.216600Z

and when each one finishes, see if its the last one to finish and then fire off the http request if so

emccue 2021-06-23T03:20:18.216800Z

(defn maybe-send-e [db]
  (if (= #{:a :b :c :d}
         (:process-state db))
    {:db db
     :fx [[:http-xhrio ...]]}
    {:db db
     :fx []}))

(rf/reg-event-fx
  ::start
  (fn [{:keys [db]} _]
    {:fx [[:http-xhrio [:on-success [::got-a]]
          [:http-xhrio [:on-success [::got-b]]
          [:http-xhrio [:on-success [::got-c]]
          [:http-xhrio [:on-success [::got-d]]]}))

(rf/reg-event-fx
  ::got-a
  (fn [{:keys [db]} [_ a]
    (-> db
        (update :process-state conj :a)
        (assoc :somewhere a)
        (maybe-send-e))))

emccue 2021-06-23T03:20:22.217Z

and so on

emccue 2021-06-23T03:20:37.217200Z

and then make sure to also handle on-failures

emccue 2021-06-23T03:20:40.217400Z

@huxley

emccue 2021-06-23T03:21:40.217600Z

that would be the explicit way if the requests had some data dependency

emccue 2021-06-23T03:22:53.217800Z

it sounds like your main concern is rate limiting so that might miss the mark somewhat, but implementing your own effect handler is somewhat tedious so that would be the explicit way without making a new mechanism

Oliver George 2021-06-23T03:33:18.221200Z

Question about app-db form state related to file fields. Normally I update app-db based on form field input change events but for "file" fields I'm fetching js/FormData from the htmlelement in my re-frame submit handler which feels ugly and dependent on stable dom rendering when handling submit.

(defn samplefile-submit-click
  [{:keys [db]} _]
  {:app/retrieve-file-submit
     {:form-data (js/FormData. (.getElementById js/document "samplefileupload"))
      :success-v [:app/-retrieve-samplefile-submit-success]
      :failure-v [:app/-retrieve-samplefile-submit-failure]}})

Oliver George 2021-06-23T03:35:52.222600Z

Do you treat upload forms differently to regular data entry forms?

p-himik 2021-06-23T09:07:40.226200Z

No. I extract File objects myself, put them in the state, and construct FormData manually. Of course, there's no reverse direction of the data flow - there are no subscriptions that set the input back. It can create issues during code reloading (the form will appear blank but app-db will have the file), but in most of my use-cases I replace the input with some representation of the file (usually by using object URLs) when it's available, so it works out just fine. Alternatively, if that form can be reused, you can create a Reagent form and then use it from re-frame.

Oliver George 2021-06-29T00:53:02.244200Z

Thanks for this.

Oliver George 2021-06-23T03:37:42.223300Z

Sample form to clarify

Oliver George 2021-06-23T03:45:49.223700Z

Related react doco: https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag

superstructor 2021-06-23T03:51:57.224Z

Welcome :thumbsup: Thanks for the report @rberger

rberger 2021-06-23T06:39:56.225700Z

Is there now a way to make codox/docstrings work with reg-event-* and subscription declarations? Or any other way to have inline documentation that can flow into codox documentation?

p-himik 2021-06-23T09:08:29.226400Z

FWIW you can document the handler functions themselves. But I'm not sure how useful it would be.

emccue 2021-06-23T13:24:46.228600Z

@rberger You can create a thin macro over reg-event-fx and subscription declarations that will insert a named function in the namespace bound to a var

emccue 2021-06-23T13:26:09.228800Z

(defmacro my-reg-event-fx
  [& args]
  (... a sprinkle of parsing ...))

(my-reg-event-fx
  "Wow, what a function!"
  ::something
  (fn [{:keys [db]} [_ ...]]
    ...))

emccue 2021-06-23T13:27:03.229100Z

;; expands to 
(defn handler:something
  "Wow, what a function"
  ...)

(rf/reg-event-fx
  ::something
  handler:something)

1👍
rberger 2021-06-23T17:00:16.231Z

Thanks @emccue I will give that a try!

p-himik 2021-06-23T09:03:30.225900Z

There is: https://github.com/day8/re-frame/blob/master/docs/Solve-the-CPU-hog-problem.md#forcing-a-one-off-render But I would definitely not use it here simply because you're changing your re-frame workflow to, as far as I understand, work around some React component issues. Instead of doing that, create a thin Reagent wrapper around that component and work around that problem there. It will become much simpler in the end, much easier to reason about, and easier to reuse.

p-himik 2021-06-23T09:07:40.226200Z

No. I extract File objects myself, put them in the state, and construct FormData manually. Of course, there's no reverse direction of the data flow - there are no subscriptions that set the input back. It can create issues during code reloading (the form will appear blank but app-db will have the file), but in most of my use-cases I replace the input with some representation of the file (usually by using object URLs) when it's available, so it works out just fine. Alternatively, if that form can be reused, you can create a Reagent form and then use it from re-frame.

p-himik 2021-06-23T09:08:29.226400Z

FWIW you can document the handler functions themselves. But I'm not sure how useful it would be.

p-himik 2021-06-23T09:10:54.226600Z

> implementing your own effect handler is somewhat tedious Not at all, given that it will be a thin wrapper around :http-xhrio. You don't have to reimplement the whole wheel, just add a couple of atoms to track the queued requests and the in-flight requests, and that's it.

micahasmith 2021-06-23T12:02:46.227500Z

if you're starting a new reframe project, what template/scaffolding is recommended to use?

2021-07-01T03:42:47.250500Z

Easy question https://github.com/day8/re-frame-template

2021-07-01T03:45:44.250900Z

I'm a beginner and I totally love to have a structured introduction to a new tool. This template is what you're looking for

p-himik 2021-07-01T07:35:05.251400Z

And that link has already been posted here. ;)

p-himik 2021-06-23T12:05:15.227600Z

I would recommend none. Figure out what components you need, find libraries that cover those needs, choose the ones you like and use them freely.

micahasmith 2021-06-23T12:05:50.227800Z

but i dont know what i dont know

p-himik 2021-06-23T12:08:15.228Z

If FOMO is strong, then just take a look at what some existing templates use, and research those libraries.

p-himik 2021-06-23T12:09:10.228200Z

IMO unless you made a template yourself and you create new projects rather often, templates have more downsides than upsides.

emccue 2021-06-23T13:24:46.228600Z

@rberger You can create a thin macro over reg-event-fx and subscription declarations that will insert a named function in the namespace bound to a var

emccue 2021-06-23T13:26:09.228800Z

(defmacro my-reg-event-fx
  [& args]
  (... a sprinkle of parsing ...))

(my-reg-event-fx
  "Wow, what a function!"
  ::something
  (fn [{:keys [db]} [_ ...]]
    ...))

emccue 2021-06-23T13:27:03.229100Z

;; expands to 
(defn handler:something
  "Wow, what a function"
  ...)

(rf/reg-event-fx
  ::something
  handler:something)

1👍
pavlosmelissinos 2021-06-23T16:24:03.229400Z

That's solid advice in general but if we're talking about beginners, I don't think FOMO is the problem. Beginners need a closed garden and cljs/re-frame doesn't have one afaik. Ego depletion/decision fatigue is a thing! I really believe there should be a guide that says, ok, here are some conventions that work 70-80% of the time. That way you have something to begin with and if you outgrow the conventions you're still able to replace a block with another (in other words, leave the garden).

p-himik 2021-06-23T16:35:52.229800Z

Not sure what you mean by a "closed garden" here. Apart from those 20-30%, all conventions and maintained/finished libraries work just fine. When it comes to libraries, if a person is not sure what they need or don't want to research too hard, they can just pick one at random. When it comes to conventions - same thing, although here it's harder to look them up because there are no GitHub repos with conventions. But there's this documentation page that describes one: http://day8.github.io/re-frame/App-Structure/ FWIW, re-frame documentation mentions this template: https://github.com/day8/re-frame-template

pavlosmelissinos 2021-06-23T16:50:31.230500Z

By "closed garden" I mean limiting the information/functionality the user is exposed to. Beginners do not need a lot of what reframe offers. > When it comes to libraries, if a person is not sure what they need or don't want to research too hard, they can just pick one at random. Let me answer that with a question. Which is more authoritative? Randomly picking shadow-cljs or the maintainers of re-frame telling you that it's good enough for most of your needs? The links you shared are useful but there's other stuff (not part of the original question, granted) that's also important, e.g. state management. How should you organize your subscriptions? Should you have a single subscription for the whole page or multiple smaller ones?

p-himik 2021-06-23T16:56:07.230800Z

> Which is more authoritative? Re-frame maintainers develop a very special kind of software. IIRC they develop desktop apps with web technologies, that's it. Whatever they recommend, can be affected by that fact. If I want to develop a mobile React Native application, I definitely should not listen to their suggestions unless they come from an experience with such apps. > How should you organize your subscriptions? It is very well documented.

rberger 2021-06-23T17:00:16.231Z

Thanks @emccue I will give that a try!

rberger 2021-06-23T17:37:43.231200Z

@micahasmith I have a minimal template repo I use cause it helps me cross the barrier of the “Blank Page Syndrome” when I’m starting a new project https://github.com/omnyway-labs/cljs-shadow-reframe-reagent-template

1👍1
2021-06-23T18:38:31.231500Z

@emccue I have currently created a similar ugly creation to yours, but I don't like it at all. As I mentioned, I tried to simplify it by using async-flow, but it made things even more complicated. Rewriting http-xhrio in my own fashion seems cool and minimizes the amount of code I need to write, because it's only a few lines

micahasmith 2021-06-23T18:55:39.231900Z

ty @rberger!