Fork me on GitHub
#re-frame
<
2017-03-13
>
tagore00:03:51

Sorry, was gone, for a bit...

tagore00:03:12

But... means "ecosystem" pretty much.

tagore00:03:59

We've talked before btw about things like this- I think I pointed out redux-saga to you a while back.

tagore00:03:52

I recall you saying you didn't love the approach, I'd like to take a closer look at what you came up with as an alternative.

tagore00:03:01

ooks interesting on a first look.

tagore00:03:33

Anyway, when I say buyt it's not a criticism of re-frame compared to redux, say.

tagore00:03:54

It' more like... well there's a lot of nice stuff around redux (like 'styled-components,' for instance, which is basically the best thing ever) and I'm curious about the experience of doing production work in re-frame.

tagore00:03:21

I'm curious because I'm considering using it for a new project, so... essentially because I really like your approach.

superstructor01:03:05

We’ve got a ~20k line and rapidly growing re-frame + Material-UI app in production @tagore Have previously used Redux. I can say as a personal observation that re-frame is hands down the best thing I’ve ever experienced for building front-end apps. I certainly wouldn’t consider going back to Redux.

tagore01:03:46

@superstructor OK, well that is good to hear.

tagore01:03:35

I mean- on some level I feel like you should make your own judgments, but... it's nice, before leaping into the void, to hear that others have done so withut falling to their deaths 😉

tagore01:03:07

I will say that the codebases I'm working on at the moment are a lot bigger than that, but...

tagore01:03:06

Well, actually there is a real but there...

tagore01:03:40

It's amazing how much of a mess you can make with 200k lines of Angular...

tagore01:03:25

Especially when many of them are clever ad-hoc sub-frameworks.

mikethompson01:03:44

@tagore regarding redux-saga alternatives ... here is an example which is specific to startup (there is breif discussion about comparisons to redux-saga at teh bottom) https://github.com/Day8/re-frame-async-flow-fx/blob/develop/README.md

tagore01:03:05

Yep- I was referring to that...

tagore01:03:43

I don't now if you remember but I think I pointed out redux-saga to you last spring, actually.

mikethompson01:03:55

i know what you mean about ecosystem .... the bigger the better

mikethompson01:03:12

i love the idea of leveraging what other smart people have done

tagore01:03:26

We had a kind of long conversation about side-effects/representing them as dara, IIRC.

mikethompson01:03:48

Right, yes, I went looking at it. i realised it was fundamentally a way of coding state machines

tagore01:03:05

Yep, exactly.

mikethompson01:03:05

At least that was my interpretation

tagore01:03:30

No, I think you are 100% correct there.

mikethompson01:03:14

So when you take that view, and you realise that events should be the FSM triggers

mikethompson01:03:26

ANd you end up in a different place to redux-sagas

mikethompson01:03:32

Well, at least I did :-)

tagore01:03:53

Most things that can be represented as "flows" really are just that. and it's nice to have a formal model rather than lots of ad-hoc implementations.

tagore01:03:34

Hmm- well I tend to think of sagas as state machines, tbh 😉

tagore01:03:01

I certainly write them that way.

tagore01:03:23

It's just not as formal.

tagore01:03:36

redux-saga is a little weird though, cause it mixes concerns....

mikethompson01:03:10

Yeah, it puts state outside of the main state container

mikethompson01:03:18

(the state of the FSM)

tagore01:03:43

Half of it is essentially not-very-formal state machines, and the other half is kind of like core.async.

mikethompson01:03:01

It captures state within the ES6 generator functions themsleves

tagore01:03:32

Hmm- I understand 90% of that

tagore01:03:09

I will say that I do like re-frame's approach...

tagore01:03:51

I've done a lot of redux (am doing a lot, really,) I've done talks n the subject, and...

tagore01:03:56

I'm inclined to think that JS is a Lisp- just not a very good Lisp.

tagore01:03:24

But the ecosystem thing is real.

mikethompson01:03:54

We do get to use a fair bit of react

mikethompson01:03:29

That's the nice thing about using reagent

mikethompson01:03:45

Interoperates reasonably well

mikethompson01:03:53

Anyway, i really do have to go now

tagore01:03:10

Yep- well interop is good in clojure/clojurescript, but...

tagore01:03:47

But... webpack

tagore01:03:43

In theory it could be made to work with cljs, but... there's always a but.

tagore01:03:42

That said, while I don't think we'll be moving to re-frame where I work...

tagore01:03:47

I'm inclined to think that for my new thing I'd rather be doing clojurescript and re-frame.

tagore01:03:01

Btw, I've been reading the docs, and I'm impressed- I've been following re-frame for a long time, and I like where you're going with it.

tagore01:03:48

You've done some very interesting stuff in the last year

mikethompson06:03:00

@tagore yes, versions 8 and 9 (last year) were a substantial step forward, both for the programming model and the docs

andre06:03:45

with the re-frame i can write RN applications without errors and without a need to debug code at all, but only two kind of problems happen sometimes, and they bring pain 1) parinfer breaks reagent view, it compiles fine but crashes in runtime, so here would be great to have devcards analogue , i'm thinking about it 2) runtime error in the event handler, very rare case, but here re-frisk сould help, it would be helpful if i could see event data which cause the error, but now re-frame provides only add-post-event-callback, here would be greate to have add-pre-event-callback

andre06:03:08

@mikethompson maybe you can advise something on the second point, thanks

mikethompson07:03:57

Something more than the debug interceptor?

andre07:03:52

#236 yes it's like what I'm looking for

joshkh13:03:10

i have an effect similar to https://github.com/Day8/re-frame-http-fx that takes from a channel (http request) and dispatches the results to be saved in my state. i want to close any previous channels from the request so that i'm only returning the results from the most recent request. my current method is to store the channel in app-db whenever the parent handler event is called, but first close any channels in that location before dispatching the effect. i find myself doing this a lot... is there a better way than my following example? can i move the channel closing somewhere outside of the starting event?

(reg-event-fx
  :qb/fetch-preview
  (fn [{db :db} [_ service query]]
    (let [new-request (fetch/table-rows service query {:size 5})]
      {:db      (-> db
                    (assoc-in [:qb :fetching-preview?] true)
                    (update-in [:qb :preview-chan] (fnil close! (chan)))
                    (assoc-in [:qb :preview-chan] new-request))
       :im-chan {:on-success [:qb/save-preview]
                 :chan       new-request}})))

joshkh13:03:17

the simple effect being..

(reg-fx
  :im-chan
  (fn [{:keys [on-success chan]}]
    (go (dispatch (conj on-success (<! chan))))))

danielcompton21:03:44

@joshkh you could construct the channels in a let, then issue several of your queries, in the callbacks close over the channels so you can reference them when they come back. Not sure if I'm understanding correctly, but you shouldn't be closing the other channels when you get a message in one of them. Using alts! or alt! is safer

joshkh21:03:53

thanks @danielcompton . the simple scenario would be: i have a button that, when clicked, fires an event that makes an HTTP request and stores the results to be displayed. if i click the button over and over and then stop i'm not guaranteed that final result is from the last event fired due to the async behavior of the ajax call.

joshkh21:03:25

in clicks one through three, the results from click two might arrive last.

danielcompton21:03:26

right. maybe you should cancel a query when the next one is issued?

danielcompton21:03:41

or order their results?

joshkh21:03:38

i think that's what i'm doing now - canceling the query by closing previously opened channel and then replacing it with the new request channel.

joshkh21:03:49

i might be doing exactly what i'm supposed to! it's just that i'm storing short lived channels in my app state and i'd imagine that's no bueno for serialization.

limist22:03:43

Not strictly a re-frame issue, but... Does anyone have experience using Chart.js with reagent? In particular, I started with the example form-3 component here: https://gist.github.com/edwthomas/b1f653405e2827357133f7e3c245bea0 Then I wanted to handle the case of :component-did-update and am not sure how to do it. This code, for example, almost works, but has a problem:

(defn chartjs-component
  [{:keys [canvas-id type data options]}]
  (reagent/create-class
   {:display-name "chartjs-component"
    :component-did-mount
    (fn [this]
      (js/Chart. (.getContext (.getElementById js/document canvas-id) "2d")
                 (clj->js {:type type
                           :data data
                           :options (merge chartjs-global-config options)})))
    ;; Initially unclear how to have charts update automatically, but
    ;; looked at the reagent/core docs and found reagent/props has the
    ;; new/changed args:
    :component-did-update
    (fn [this]
      (js/console.log "component-did-update this" (pr-str (js-keys this)))
      (let [{:keys [data options]} (reagent/props this)]
        #_(reagent/force-update this)  ; does not work
        (js/Chart. (.getContext (.getElementById js/document canvas-id) "2d")
                   (clj->js {:type type
                             :data data
                             :options (merge chartjs-global-config options)}))))
    :reagent-render (fn [] [:canvas {:id canvas-id :width "640" :height "480"}])}))
The problem with the :component-did-update function above, is that another chart.js chart object is created, and weird behavior then results from having two chart objects. Instead, I'd like to either destroy the old chart and draw a new one, or, use the Chart.js update method to take the new data. Either way, I need some kind of reference to the old/original chart object; and I don't see/understand how to get that from the this passed in to the function under component-did-update Any help appreciated!

kishanov23:03:11

in your case you’re passing properties correctly so you have to find out how to use update in chartjs context

kishanov23:03:42

if I remember correctly they have update method which should be called when the original dataset has changed

limist23:03:50

@kishanov Yes, that's the problem: is the actual chart.js object/instance somewhere in the this object? If so, where? Once I have it, I can invoke the chart.js update method

limist23:03:13

What I don't quite get (and didn't see docs for) is what exactly the this object is, as received by the form-3 functions...

kishanov23:03:15

@limist I don’t think it wil be anywhere in this object, cause it was created by chartjs after you rendered it. I think in component-did-update you can find chartjs object via jquery selector and do imperative update there

limist23:03:40

@kishanov Ugh. That seems rather...inelegant. 🙂

mikethompson23:03:13

Does this help ? https://github.com/Day8/re-frame/blob/master/docs/Using-Stateful-JS-Components.md (I haven't actually tried to understand the specifics of your problem, just throwing this link over the wall) ?

mikethompson23:03:56

@limist ^^^ Notice the various links down the bottom of that page too.

limist23:03:25

@mikethompson Yes, that does/will help, thanks! Good to know the right terminology of the problem for starters; will take a closer look and start some refactoring.