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
2020-08-05T00:45:44.197800Z

There are only two kinds of people in this world: 1. Those that don't know CSS 2. Those that think they do, except they don't. Not really.

1😂
2020-08-05T01:36:19.198100Z

Further Notes: 1. to reduce noise, you should make check-spec-interceptor a global interceptor (a new feature) 2. It appears as if your calls to interfaces/invoke and io/display-notification are side effecting and would ideally be modeled as effects (ie. use reg-fx) 3. In https://github.com/realgenekim/re-frame-event-graph/blob/master/resources/trello-events.cljs#L355-L363 it appears you are using events instead of function calls. IMO, you should have a function call reset-card not an event. This function would be given db arg and return a modified db. Then you simply call that function in that event handler ... don't dispatch an event to do it. Events are meant to model user intent, not model the low level machinery - good old functions calls do that just fine. 4. I'm sure I don't need to tell you that you should clean up all those side effecting dispatch calls in reg-event-db handlers ... but I will any way, just in case :-) BTW, I know I haven't got the the event knot yet. More later when I get a bit more time.

genekim 2020-08-05T02:48:52.200Z

This is mind-expanding. 🤯🤯 Thank you!

1➕
genekim 2020-08-05T04:35:32.200300Z

This is beautiful…

(>defn reset-card
  [db] [map? => map?]
  (assoc db :current-card-comments []
            :current-card-attachments []
            :new-comment-text ""))

(>defn set-list
  [db list-id] [map? string? => map?]
  (assoc db :selected-list list-id))

(comment
  (-> {:a 1}
      reset-card
      (set-list "abc")))

genekim 2020-08-05T05:29:12.200500Z

This is even more beautiful — as imperative stuff moves to more declarative…

(re-frame/reg-event-fx
  ::select-board
  [check-spec-interceptor]
  (fn [{:keys [db]} [_ board-id]]                           ; currstate, and new state
    (println "::select-board: " board-id)
    {:dispatch-n [[::save-and-clear-searchbox]
                  ; if moving card, make sure focus is in search box
                  (when (= (:left-pane-view db) :leftpane-moving-board)
                   (io/focus-searchbox ::focus-searchbox))
                  [::load-board-lists board-id]
                  [::select-board-next-leftpane-state]]
     :db       (dbh/select-board db board-id)}))

genekim 2020-08-05T06:16:59.200700Z

Wow, this is nice…. made my first reg-fx.

(re-frame/reg-fx
  :load-lists
  (fn [board-id]
    (check-and-throw string? board-id)
    (println ":load-list: fired off go-routine: board " board-id)
    (interfaces/invoke interfaces/trello {:command :load-lists
                                          :board-id board-id
                                          :callback ::callback-load-board-lists})))

2020-08-05T16:35:46.202200Z

I would look at react-cytoscapejs for rendering networks with a functional interface. I am using it at work and it seems decent.

Jose Varela 2020-08-05T16:37:24.202400Z

Looks awesome! Thanks for the tip

lwhorton 2020-08-05T16:43:41.203300Z

https://github.com/Day8/re-frame/issues/218#issuecomment-252470445 i’m thinking about this introduction of the syntax sugar derefs, and i’m curious how to do this:

lwhorton 2020-08-05T16:44:24.204300Z

(def my-component [x]
 (let [my-local-val (r/atom) 
       some-dynamic @(subscribe [:foo x])] 
….)

lwhorton 2020-08-05T16:46:09.205500Z

if i want local component state, but i’m using the syntax sugar form-1, that ratom is going to get blown away every rerender, no? do i just have to raise the ratom into a let, and return a renderer fn (form 2)?

(fn [x] (let [some-dynamic @(subscribe [:foo x])

lilactown 2020-08-05T16:47:33.206500Z

yeah if you’re use a local ratom, then you should use a form-2 (or with-let). to avoid those corner cases as explained in the issue, you can subscribe in the body of the returned function

1👍
dpsutton 2020-08-05T17:11:31.206700Z

r/with-let is the bees knees

2👋
Jacob Emcken 2020-08-05T18:24:49.212Z

I want to trigger a CSV parse (which is async by nature using the lib node "papaparser"). So I would like to "subscribe" to both the (CSV) file and the delimiter to trigger re-calculation of a CSV preview. I'm not sure what would be a good approach. I've been looking a http://day8.github.io/re-frame/subscriptions/ and if the CSV parsing had been synchronous, I would have put the re-calculation in the Layer 3... but now I'm at a loss.

Shako Farhad 2020-08-05T19:50:24.212200Z

If the triggering of the delimeter is done by the user you can use a :on-click or :on-change to trigger a dispatch event that updates the CSV data. Sorry if that is not helpful. I am not quite sure how your app works. :x

Jacob Emcken 2020-08-05T20:06:46.212600Z

The on-change is supposed to change the state of the delimiter in app-db. But I also want it to trigger a re-calculation of the CSV preview. The thing is I have several options for the CSV preview parser I change individually, I want the all to trigger a re-calculation of the CSV preview on top also updating the state of app-db. I "solved" this by registering my own effect but I'm repeating myself triggering this effect with the help of reg-event-fx all the places where I either change the CSV parsing options or the CSV file itself (file chooser).

Jacob Emcken 2020-08-05T20:09:08.212800Z

I was just looking at the signal graph where it could just "listen" on changes in app-db I felt it would have been easier (with less repetition) to "subscribe" to the changes in app-db for re-calculate the CSV preview just like it is possible for views.

Jacob Emcken 2020-08-05T20:09:16.213Z

I thought I'd might be missing something

uosl 2020-08-05T20:12:12.213200Z

I have to say your use of guardrails and check-and-throw impresses me. In my code those things are nonexistent 😹

Shako Farhad 2020-08-05T20:13:55.213400Z

Let me try to understand. You select a CSV, and then you set some parsing options. Then you have a preview window that shows the result of the parse with the given CSV and the parsing options, right?

Shako Farhad 2020-08-05T20:17:05.213600Z

The preview window is the view. It subscribes to the CSV data and draws out the preview. The CSV file and the CSV parsing options are both one event. Everytime one or the other changes, you dispatch the event. The event is to rerun the parser with new inputs, and register the changes to the app-db. Then when the changes have been registered, the subscriptions are updated and the preview is updated. I think you have done it the right way from the start. 😛

Jacob Emcken 2020-08-05T20:20:25.213800Z

You might be right 🙂

Jacob Emcken 2020-08-05T20:23:41.214Z

might be = are most likely I'm going to sleep on it. Thanks.

Shako Farhad 2020-08-05T20:24:12.214200Z

Good night and good luck!

genekim 2020-08-05T20:30:43.214400Z

Haha — your ability to write and run code without Guardrails and check-and-throw impresses me! Seriously, I pass in wrong stuff all the time, sometimes as an accident or misinterpreting the API. (Just yesterday in my first reg-fx posted above, at first I accidentally passed in [board-id] instead of board-id and would have spent 10+ minutes trying to figure out why I was getting strange behavior or unreadable, long exception.)

genekim 2020-08-05T21:14:47.214600Z

@regen WOW!!! Thank you! That’s awesome!!!

1🎉
genekim 2020-08-05T21:14:50.214800Z

…and a relief!!!

uosl 2020-08-05T21:23:40.215Z

I am able to now, but maybe not when touching it again next year. 😅 I do see real value in type signatures as documentation, and wish it was more common to use them in Clojure!