Fork me on GitHub
#re-frame
<
2016-09-07
>
tom02:09:08

That's one way, I'll consider it some more. I'm using the YouTube video API. Which provides its controls in a big old global mutant they've been using since like 2007. I figure talking to the global that controls playback must happen in an effects handler, which is coupled right with the state received from props in a JSX parent, so nothing really reaches down to views except for a couple couple things (like adding or modifying or destroying the iframe).

rorydouglas02:09:54

is there a migration guide for 0.7->0.8 anywhere?

rorydouglas02:09:01

i’ve converted my 0.7-style middleware to interceptors (I think)

rorydouglas02:09:19

though it’s unclear how to use interceptor factories

rorydouglas02:09:13

before I add a vector of standard middleware that I passed to register-handler

rorydouglas02:09:29

this doesn’t seem to work anymore

rorydouglas02:09:48

nvm i think i’ve figured it out

rorydouglas02:09:21

switched my wrapping middleware to a before/after interceptor pair

rorydouglas02:09:31

still not clear on how to use enrich etc in the 0.8 world

mikethompson04:09:55

enrich has been turned into an Interceptor, but your use of it shouldn't need to change. It should work exactly as before.

curlyfry05:09:37

Missed the changes doc before, it's great!

curlyfry05:09:34

@mikethompson: The doc says "You can now run and debug re-frame tests on the JVM." What does this mean in practice? Are there any examples of how this works, and does this mean it is easier to use JVM testing libraries for my handlers (such as midje)?

mikethompson05:09:27

@sam.roberton has been working on https://github.com/Day8/re-frame-test which isn't yet documented. As an example of how it might be used, he provided this PR against the todomvc example: https://github.com/Day8/re-frame/pull/193 (not intended to be merged, just used as an example)

pepe05:09:39

@mikethompson yes, I just migrated mid-size app without any hassle. I created fresh new 0.8 and looked in it for the reference. And I like the new subs and handlers a lot.

mikethompson07:09:08

@pepe my hope was that most re-frame apps will work with v0.8.0 with no changes whatsoever. (other than some warnings in the js/console about renamed functions.)

pepe08:09:49

@mikethompson nobody likes warnings in the console 😉

snoe08:09:38

I've been wondering, is there a practical difference between (def my-sub (rf/subscribe [:query])) (defn component [] [:div @my-sub]) and (defn component [] (let [my-sub (rf/subscribe [:query])] (fn [] [:div @my-sub]))? We use the former and we're pretty happy with it because a) form-1 vs form-2 components b) the reactions can be reused in other components c) the register-sub and the reaction can be close together d) by using a var you get a warning if you typo whereas having multiple subscribe calls to the same query has no compile time protection. But looking at the docs and the 0.8 changes I'm surprised that the latter seems to be preferred. What's the advantage that I'm missing?

mbertheau09:09:30

I think with Form-2 the subscription will only be created when the component is used somewhere, and it will be deleted when the component isn't used anymore. Not sure though that this outweighs the benefits of Form-1 you mention.

rorydouglas12:09:52

@mikethompson @pepe yes I’m still concerned that I’m not grokking something. I had a failsafe middleware that I used in development (to stop myself accidentally wiping out app-db by returning nil from a handler :-S). It was the typical before/after wrapping middleware. I initially converted that using the pattern in https://github.com/Day8/re-frame/blob/master/docs/Interceptors.md#wrapping-handlers & then included that interceptor in my interceptor vector e.g. [trim-v failsafe]. That was triggering the warning about a function instead of an interceptor i.e. not a warning about renames, but an indication I was doing something wrong

rorydouglas12:09:15

so it seems the correct way to convert that kind of mw is ->interceptor with :before/`:after` modifying :effects/`:coeffects` as necessary. I guess the docs gave me the impression I needed to write an interceptor factory function that takes a handler

rorydouglas12:09:17

@mikethompson i guess my question is more: in what kind of situations do you envisage people writing custom handler wrappers a la db-handler->interceptor?

mikethompson13:09:28

@snoe you only want a subscription to be "active" when a component is using it. Making it global means it is active 100% of the time. There are plenty of cases where you just don't want that. When the component disappears you want the subscription to disappear. @rorydouglas I hadn't really imagined people writing their own wrappers. But did imagine people would come up with their own interceptors semi regularly.

manutter5113:09:18

@rorydouglas I considered writing a similar interceptor, but I decided not to, on the grounds that if I write a handler wrong, it fails fast and hard so that I know I need to fix the handler. A failsafe interceptor might mask a bug by returning a valid (but incorrect) copy of the original app-db

mikethompson13:09:20

;; untested 
(def failsafe 
    (re-frame.core/->interceptor 
       :id     :failsafe
       :after  (fn [context]   (assert (some->  context :effect :db)))))

mikethompson13:09:24

But be careful using it.

mikethompson13:09:51

-fx handlers doen't have to return a :db effect

mikethompson13:09:11

So this only make sense on -db handlers

rorydouglas13:09:18

i’d figured out how to write the interceptor already

mikethompson13:09:41

But you shouldn't be using this interceptor ...

rorydouglas13:09:06

i think my point is more about the documentation - coming at it from a migration standpoint, it seemed to imply I’d need to write something like db-handler->interceptor

rorydouglas13:09:18

yeah this was def a quick ’n dirty dev hack

rorydouglas13:09:09

nice, i’ll try that after approach

rui.yang13:09:58

Hi wonder what is the best way of handling form input in re-frame. my app seems a bit slow when user types in the input.

rui.yang13:09:33

my app currently does input->on-change->change model while user typing->ui get updated

mbertheau13:09:48

use on-blur instead

rui.yang13:09:51

wonder if there is a better way that only updating model on blur

rui.yang13:09:58

I tried on-blur

rorydouglas13:09:14

@rui.yang and it didn’t work for you?

rorydouglas13:09:37

i’ve used on-blur (via re-com input-text component) successfully in the past

rui.yang13:09:38

in my memory the ui didn't change

rui.yang13:09:51

I am trying it again now

rorydouglas13:09:16

if you’re using your own text input component you could take a look at re-com’s input-text for reference

rui.yang13:09:29

my understanding is that UI is always a function (rendering function) of your app-db. since app-db didn't change until on-blur, so ui didn't respond to user input

rorydouglas13:09:02

i think you still need to accumulate char-by-char changes in an internal atom

rorydouglas13:09:16

then reset! to app-db state on-blur

rorydouglas13:09:01

this should be faster than updating app-db every keystroke, since you won’t be triggering reactions etc

rui.yang13:09:50

@rorydouglas thanks for the tips. it is less obvious in browser, but pretty obvious in mobile

rui.yang13:09:56

I'll check it out

rui.yang13:09:29

looking at that logic, not that straightforward

rorydouglas14:09:44

@rui.yang maybe just use the re-com component then? 🙂

curlyfry16:09:37

@mikethompson: Thanks for the info on testing!

lwhorton16:09:39

if I wanted to inject a “watcher” that sits and observes the dom, is that an efficient way to do this? i’m trying to come up with a scheme for custom tooltips, and I think for the consumer the simplest API would be [:div {:tooltip “some text”}]. I would need a way to know when a new attribute-tooltip appeared in the dom, and respond accordingly.

lwhorton16:09:55

normally I could do something like what livequery does, and maintain a cache of dom nodes and watch for insertion/deletion, but I’m wondering if there’s a more clever way to handle this with reagent...

lwhorton16:09:14

I suppose another alternative would be something like

[tooltip {:label “some text}
  [:div “foo bar”]]
Where you compose a component inside a tooltip. That might be simpler than doing some global dom watching.

shaun-mahood17:09:07

@lwhorton: Do you want it all to work with normal HTML tooltips, or is it going to be run using CLJS when they mouseover?

lwhorton17:09:25

sadly the business requirements do not “like the look” of standard html tooltips, so we have to reinvent the wheel

lwhorton17:09:00

i’m testing it out with a simple mouse-enter/mouse-leave dispatch + subs and a top level container to see if it’s performant enough.

shaun-mahood17:09:28

@lwhorton: Yeah, that's what I was thinking about. You could probably add the mouse-enter/mouse-leave directly to the components - what does the top level container give you that you can't do directly?

lwhorton17:09:11

z-index issues are resolved immediately, also the top component can do the magic number manipulation to make sure a tooltip always fits on screen

lwhorton17:09:11

there are always a few pieces in an app that virtually-always end up needing to be “at the root” or 1 down… things like a notifications message, tooltips, etc.

lwhorton17:09:35

otherwise you end up with zindex issues that are just unbearable (i find)

shaun-mahood17:09:16

Oh yeah, that makes sense - I tend to forget about z-index stuff right up until the moment I want to break my computer.

mikethompson21:09:40

@lwhorton re-com has popup tooltips for buttons - which may act as inspiration. It was a little tricky. You have to be careful of cliping, etc.

mheld21:09:01

hey y'all

mheld21:09:17

anybody here use the re-frame-http-fx lib?

mheld21:09:50

getting some weird issues re: params

mheld21:09:58

in that the params aren't being sent over at all

mheld21:09:26

is this a valid usage of reg-event-fx (expecting to call (dispatch [:login email password])

martinklepsch21:09:03

@lwhorton I've previously used goog.ui.Tooltip, have you considered that for the tooltips? It escapes React a bit but it's working very well

martinklepsch21:09:10

;; [goog.html.SafeHtml :as safe-html]
;; [reagent.core :as reagent])
;; (:import [goog.ui Tooltip]))
(defn tooltipped [{:keys [tip]} body]
  (let [tt       (atom nil)
        tip-node #(safe-html/create "span" #js {:class "br1 ph2 pv1 bg-black-70 white f6"} %)]
    (reagent/create-class
     {:component-did-mount (fn [this]
                             (let [tt (reset! tt (Tooltip. (reagent/dom-node this)))]
                               ;; Position tooltip relative to dom node instead of cursor:
                               ;; (set! (. tt -getPositioningStrategy)
                               ;;       (fn [_] (js/goog.ui.Tooltip.ElementTooltipPosition. (reagent/dom-node this))))
                               (.setSafeHtml tt (tip-node tip))))
      :component-will-unmount (fn [this] (.dispose @tt))
      :component-did-update (fn [this] (->> (reagent/props this) :tip tip-node (.setSafeHtml @tt)))
      :reagent-render (fn [{:keys [tip]} body] [:span body])})))

martinklepsch21:09:07

+ you can just get on with life and don't worry about clipping and other things

mikethompson21:09:37

@martinklepsch is that atom (5th line) a reference to a reagent.core/atom ?

martinklepsch21:09:04

@mikethompson it's not and I think it doesn't matter but for consistency probably still a good idea