Fork me on GitHub
#re-frame
<
2016-08-18
>
mikethompson01:08:50

My other thought is: do you have two concurrent instances of re-frame-async-flow happening?

luposlip06:08:24

Anyones got an example of using re-frame (or similar) to enable server side FRP?

mbertheau08:08:04

I'm assuming it has something to do with the keystroke/event handlers of the browser and reagent/react interleaving, but I don't understand the internals enough to know what I can do about it.

mikethompson08:08:54

@lwhorton can you please try the latest. I've fixed the two "bugs" (circumstances) I imagined might be contributing to what you were seeing. [day8.re-frame/async-flow-fx "0.0.6"] [re-frame "0.8.0-alpha12"] If you still see the same problem, I'll have to get a gist from you to investigate further.

mikethompson08:08:34

@mbertheau I don't normally do char by char processing. Can you perform your test on these (pure reagent) widgets (see the widget under "Demo" heading) http://re-demo.s3-website-ap-southeast-2.amazonaws.com/#/input-text

mikethompson08:08:17

and then try your test again with :change-on-blure? set to false

mbertheau08:08:00

Ah, so you just commit to app-db on blur?

mikethompson08:08:24

I have that luxury

mikethompson08:08:53

BUT ... a widget like the one in re-com should give you the option of on-change processing

mikethompson08:08:29

Before going any further, I'm just making sure a pure reagent widget (no re-frame) works for you

mbertheau08:08:58

I have it too for most of my inputs. Nice! Thanks. I can't reproduce it on the re-com demo site.

mikethompson08:08:50

It looks as if the tiny pause due to processing each event is still enough to miss chars. So you'll have to use a widget which stores state in a local atom. AND then dispatches.

mikethompson08:08:09

A bit like the re-com widget does

mbertheau08:08:27

I never actually change the text in the input in these events, so I guess at first I can avoid updating the part of app-db that triggers a change to the input's value attribute.

mccraigmccraig08:08:25

@mbertheau: we do char-by-char processing on slow (mobile) processors - we found that we needed to put the text-field value into a local atom or we lost chars on some phones

mbertheau09:08:36

@mccraigmccraig: @mikethompson: I see. That also answers my question about inputting combining characters in korean and other languages. Thanks for the insight!

luposlip09:08:21

Sorry for asking the same question twice: anyone here knows about an example of using re-frame db/dispatch/subscribe for the server side? 🙂

mikethompson09:08:01

@luposlip I'm not sure what that means. You mean using re-frame on the JVM? Nodejs?

mikethompson09:08:27

Is this some sort of isomorphic requirement perhaps

mbertheau09:08:30

Hmm, if I understand correctly after looking at re-com's input-text, you can't have commit-only-on-blur on an input and be able to set the input value during the lifetime of its component without doing the internal-model dance. Since that's non-trivial, I wonder if it would be feasible to extract these parts from re-com, leaving the markup/CSS-specific parts out.

mikethompson09:08:50

From memory, the todomvc example at the end of the reagent page has a barebones input field which commits to a local atom (I think): http://reagent-project.github.io/ I have to go I'm afradi. Dinner here

Oliver George09:08:30

Hello. I see there is a 0.8 release on GitHub but it's not marked as the latest stable release. Just wanted to check if it's close.

luposlip10:08:45

@mikethompson: I’m not exactly sure either. I don’t want to do server-side rendering of react (reagent). What I want is to use re-frame’s dispatch/subscribe on the server to achieve server side FRP. Like a single framework for using FRP in both client and server, like Sente is for both server and client (and has the same'ish API).

mikethompson11:08:16

@olivergeorge At this point, I'm thinking that 0.8.0-alpha12 will be the last alpha before release

mikethompson11:08:15

I'm just syncing up satellite libs like re-frame-undo

mikethompson11:08:17

re-frame-test is getting plenty of skillful love from Sam

mikethompson11:08:17

A release-ready async-flow-fx is done

mikethompson11:08:22

Not much more to go

Oliver George12:08:37

Fantastic. Thanks for the update.

lwhorton13:08:27

@mikethompson I was fooling around with 0.0.4 and then 0.0.5. Moving to 0.0.5 fixed some issues I was having in addition to a “unknown deregister”. What also helped was to not explicitly include forward-events if I already had async-flow… figured that out after taking a look at flow’s source and seeing the dependency. Might be worth mentioning in the docs if you’re using both to only include flow. I’ll look at 0.0.6. While I have you, wrt https://github.com/Day8/re-frame-async-flow-fx/blob/develop/src/day8/re_frame/async_flow_fx.cljs#L108 can you not do (update-in db db-path dissoc) to “dissoc-in”? Until such time I don’t expect db-path to work, and thus two flows at the same time won’t be possible.

lwhorton13:08:56

@mikethompson I was also thinking yesterday about effects and particularly [this](https://github.com/Day8/re-frame/blob/develop/docs/Effects.md#db-not-always-needed) . I’m currently running with my own implementation of reg-event-fx such that :db (if not returned by an -fx) will be tacked back on to whatever was returned. Given the docs linked here, that seems to be the default behavior, but the impl doesn’t match?

lwhorton13:08:07

The reason I stumbled on this is an :after interceptor doing schema checking — hand the interceptor factory a fn to be run on :after, and it will receive a :db. But if any -fx handler fails to return {:db (:db cofx)} in addition to their other effects, [db] inside after will always be null.

mikethompson13:08:01

@lwhorton I'm not sure your dissoc-in works. For example (update-in {:a {:b {:d 4} :c 1}} [:a :b] dissoc) doesn't make a change

lwhorton13:08:02

It would depend on the path - if you had {:db {:my-flow-1 … :my-flow-2 …} and the path is [:db :my-flow-1] you would have to do some sniffing on the last

lwhorton13:08:20

(update in db path-except-last dissoc last-in-path)

lwhorton13:08:29

not sure how reliable that is 😕

mikethompson13:08:06

I just groan a bit every time I have to copy this function to another place

mikethompson13:08:57

But even as it is, there's should be no problem with two flows at the same time.

mikethompson13:08:17

Without the dissoc-in, all that's happeing is that state might not be cleaned up in the teardown

mikethompson13:08:52

Which probably won't hurt anything much

lwhorton13:08:42

I see - and if you leave it to the default path are things just keyed under :id? {:db :path-to-flows {:flow-1 … :flow-2 ...}>? in that case default has my vote 😉

mikethompson13:08:58

BTW, I don't really follow you description regarding "tacking on db" So i can't comment

lwhorton13:08:12

let me give an example ..

mikethompson13:08:51

If you don't give a db-path then the state is not even stored in app-db

lwhorton13:08:11

Ohh that’s right - dumb question. I remember now seeing it’s in an atom.

lwhorton13:08:57

(reframe/reg-event-fx
  :boot/authenticating
  (fn [cofx]
    {:http {:method :get
            :uri (:user routes)
            :success [:boot/authenticated]
            :failure [:boot/unauthenticated]
            :error [:boot/unauthenticated]}}))

;; registered as interceptor
(reframe/after valid-schema?)

(defn valid-schema?
  "Validate the given db, logging any problems to the console."
  [db]
  (let [res (s/check Schema db)]
    (when (some? res)
      (console :warn "schema problem: " res))))

lwhorton13:08:36

After a [:boot/authenticating], which only returns {:http … } and not {:http … :db (:db cofx)}, that after fn will have a null db.

lwhorton13:08:05

it just seems like cognitive overhead (but the gain of being explicit) to have every -fx handler pass-through :db.

mikethompson14:08:02

I'm confused by your code.

lwhorton14:08:12

wouldn’t be the first time someone’s said that 😛

mikethompson14:08:28

(reframe/after valid-schema?) returns an Interceptor

lwhorton14:08:43

yea that’s just a bad example, this will help:

(def default-interceptors
  [
   (when ^:boolean goog.DEBUG debug)
   (when ^:boolean goog.DEBUG (reframe/after valid-schema?))
   reframe/trim-v
   ]
  )

(defn reg-event-db
  "Register a db handler that automatically uses app-wide default interceptors.
  Optionally provide additional interceptors (as a vec) to include after the
  default."
  ([id handler]
    (reframe/reg-event-db id default-interceptors handler))
  ([id more handler]
    (if-not (vector? more)
      (console :error "re-frame: registering a handler with additional
                   middleware requires that middleware to be inside a vector.")
      (reframe/reg-event-db id (into [] (concat default-interceptors more)) handler))))

mikethompson14:08:44

For it to be used, it must be added to an event handler

lwhorton14:08:04

my own reg-event-db as well as reg-event-fx automatically register with the default interceptors^ above

mikethompson14:08:40

BTW, you don't need to (into [] (concat default-interceptors more))

mikethompson14:08:01

[default-interceptors more]

mikethompson14:08:13

re-frame will flatten and remove nil

mikethompson14:08:23

But that's an aside

lwhorton14:08:27

ah, good to know

lwhorton14:08:44

also this was written a month ago when I was brand new to clojure and “hey this seems to work” was more often than not my case

mikethompson14:08:25

Oh, right, so you have: 1. Schema checking in your default-interceptors 2. And you are using default-interceptors on all event handlers 3. But some of your event handlers don't returns a :db 4. Which means there's nothing to check?

lwhorton14:08:41

Correct, for all handlers that are reg-event-db, db is always going to be returned because that’s the way it is.

mikethompson14:08:42

So you need to make your after interceptor NOT do a Schema check if there's no :db ?

lwhorton14:08:04

Well, I’m not sure if that’s the solution or if that will get me in trouble?

mikethompson14:08:15

Seems like a solution to me

lwhorton14:08:18

i.e. if a -fx handler doesn’t return a db, is that db “gone” from the context in all future handlers?

mikethompson14:08:36

If there's not :db in :effects then there can't be any change to app-db

mikethompson14:08:45

So no need to check anything

lwhorton14:08:17

i see.. ill have to look over the interceptor code a bit more - but you’re saying the context will only update :effects (the new db) if a handler returns :db.

lwhorton14:08:19

that makes sense

mikethompson14:08:03

So to say that more correctly: do-fx (which is the interceptor which actions effects) will only perform the effects it finds in a context's :effects. And if :db is not in there, then there's no update to perform on app-db

lwhorton14:08:13

wonderful. This is a really great idea btw, i’m very impressed with the concept.

mikethompson14:08:42

You can return {} from an -fx handler which means no effects. Not sure why you'd do it. But it is valid

mikethompson14:08:53

They've got better in the last week

mikethompson14:08:10

Should be a bit clearer now

lwhorton14:08:52

I was actually reading through everything multiple times just this mon/tues.. and yes its much clearer. I’m going to make a pass again once everything is dandy within my own app to help out with some ref errors in the docs… some still point to old function names, or dont utilize [cofx] but [world] instead, etc.

mikethompson14:08:42

They need a bit of proofing

lwhorton14:08:18

btw - one more question… is there a reason forward-effects forwards the “whole stack of events”, the event that caused the forward and then the event to forward?

lwhorton14:08:12

from my perspective, I would like to reuse existing handlers and forward events to them from some control point, but can’t reuse them because the function signature is different when forwarded versus dispatched

lwhorton14:08:01

(reframe/reg-event-db
  :boot/authenticated
  (fn [db [user a b]]
    (-> db
        (db>/set-user user)
        (db>/authenticated))))

…
     :forward-events {:register :boot/load-after-public-login
                      :events #{:public/authenticated}
                      :dispatch-to [:boot/authenticated]}
…

lwhorton14:08:37

this, for example, won’t be reusable.. ill have to have a diff handler like boot/authenticated-forwarded

lwhorton14:08:09

and I couldn’t find any 100% reliable way to determine if something is forwarded versus dispatched, in which case I could use an interceptor to trim-v that first event

mikethompson14:08:08

Sorry, not following.

mikethompson14:08:14

But I'd better disappear to bed

lwhorton14:08:22

Oops, sorry — see ya.

lwhorton14:08:12

https://github.com/Day8/re-frame-forward-events-fx#tutorial In this tutorial it says "The payload of this dispatch is the entire event dispatched in the first place”. This means that a handler cannot be reused if it is the target of a forwarded event. In the normal (dispatch [:foo 1]), the handler :foo would have the fn signature of [db [args]] (without trim-v it would be [db [_ args]]).

lwhorton14:08:01

If :foo is involved in a forward-event, such as

:forward-events {:register :bar/forward
                      :events #{:bar/happened}
                      :dispatch-to [:foo]}
Then suddenly the signature of :foo has to be [db [trigger-event args]], which in this example would look like [[:bar/happened] 1]].

lwhorton14:08:22

Basically, why does this https://github.com/Day8/re-frame-forward-events-fx/blob/master/src/day8/re_frame/forward_events_fx.cljs#L19 include the whole event-v as opposed to only the payload (conj dispatch-to (rest event-v))? If it’s used internally I understand, but can we perhaps mark it so that it can be identified and removed with something like trim-v?

lwhorton15:08:54

I’m going to do some more thinking on that function signature issue to see how really impactful it is (if at all). it might be the odd-man-out case where you actually can reuse a -db handler that expects to receive a forward as well as a normal dispatch.