This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-09-07
Channels
- # admin-announcements (2)
- # arachne (1)
- # bangalore-clj (2)
- # beginners (39)
- # boot (349)
- # cider (31)
- # clara (2)
- # cljs-dev (9)
- # cljsjs (67)
- # cljsrn (7)
- # clojure (300)
- # clojure-art (4)
- # clojure-greece (11)
- # clojure-hk (3)
- # clojure-israel (1)
- # clojure-italy (17)
- # clojure-japan (1)
- # clojure-russia (33)
- # clojure-sg (2)
- # clojure-spec (41)
- # clojure-uk (86)
- # clojurescript (123)
- # clojurex (3)
- # code-reviews (1)
- # component (6)
- # crypto (1)
- # cursive (36)
- # datomic (32)
- # devcards (3)
- # emacs (11)
- # events (3)
- # funcool (4)
- # luminus (10)
- # om (28)
- # onyx (88)
- # pedestal (2)
- # re-frame (84)
- # reagent (7)
- # ring-swagger (3)
- # specter (33)
- # sql (2)
- # vim (21)
@tom Perhaps the Container / Component pattern is what you are after: https://github.com/Day8/re-frame/blob/master/docs/Using-Stateful-JS-Components.md
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).
is there a migration guide for 0.7->0.8 anywhere?
i’ve converted my 0.7-style middleware to interceptors (I think)
though it’s unclear how to use interceptor factories
before I add a vector of standard middleware that I passed to register-handler
this doesn’t seem to work anymore
nvm i think i’ve figured it out
switched my wrapping middleware to a before/after interceptor pair
still not clear on how to use enrich
etc in the 0.8 world
enrich
has been turned into an Interceptor, but your use of it shouldn't need to change. It should work exactly as before.
@rorydouglas Description of changes: https://github.com/Day8/re-frame/blob/master/CHANGES.md#breaking The migration should be pretty easy.
For more on Interceptors, see the docs https://github.com/Day8/re-frame/blob/master/docs/README.md
@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)?
@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)
@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.
@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.)
@mikethompson nobody likes warnings in the console 😉
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?
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.
@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
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
@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
?
@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.
@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
;; untested
(def failsafe
(re-frame.core/->interceptor
:id :failsafe
:after (fn [context] (assert (some-> context :effect :db)))))
But be careful using it.
-fx
handlers doen't have to return a :db
effect
So this only make sense on -db
handlers
thanks guys
i’d figured out how to write the interceptor already
But you shouldn't be using this interceptor ...
... instead you should be using https://github.com/Day8/re-frame/blob/master/docs/Debugging-Event-Handlers.md#3-checking-db-integrity
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
yeah this was def a quick ’n dirty dev hack
nice, i’ll try that after approach
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.
my app currently does input->on-change->change model while user typing->ui get updated
@rui.yang and it didn’t work for you?
i’ve used on-blur (via re-com input-text component) successfully in the past
if you’re using your own text input component you could take a look at re-com’s input-text for reference
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
i think you still need to accumulate char-by-char changes in an internal atom
then reset!
to app-db state on-blur
this should be faster than updating app-db every keystroke, since you won’t be triggering reactions etc
@rorydouglas thanks for the tips. it is less obvious in browser, but pretty obvious in mobile
@rui.yang maybe just use the re-com component then? 🙂
or wrap something like http://smikhalevski.github.io/react-text-input/
@mikethompson: Thanks for the info on testing!
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.
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...
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.@lwhorton: Do you want it all to work with normal HTML tooltips, or is it going to be run using CLJS when they mouseover?
sadly the business requirements do not “like the look” of standard html tooltips, so we have to reinvent the wheel
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.
@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?
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
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.
Oh yeah, that makes sense - I tend to forget about z-index stuff right up until the moment I want to break my computer.
@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.
is this a valid usage of reg-event-fx (expecting to call (dispatch [:login email password])
@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
;; [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])})))
+ you can just get on with life and don't worry about clipping and other things
@martinklepsch is that atom
(5th line) a reference to a reagent.core/atom ?
@mikethompson it's not and I think it doesn't matter but for consistency probably still a good idea