This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-01-16
Channels
- # beginners (11)
- # boot (21)
- # cider (12)
- # clara (6)
- # cljs-dev (7)
- # cljsjs (1)
- # cljsrn (62)
- # clojure (137)
- # clojure-austin (5)
- # clojure-italy (1)
- # clojure-nl (2)
- # clojure-russia (46)
- # clojure-spec (21)
- # clojure-uk (79)
- # clojurescript (56)
- # clr (1)
- # core-typed (1)
- # css (1)
- # cursive (3)
- # datomic (35)
- # docker (2)
- # emacs (20)
- # garden (3)
- # hoplon (8)
- # incanter (3)
- # jobs (12)
- # mount (5)
- # nginx (1)
- # off-topic (71)
- # om (8)
- # om-next (6)
- # onyx (4)
- # perun (3)
- # proton (2)
- # protorepl (5)
- # re-frame (35)
- # reagent (38)
- # ring (5)
- # ring-swagger (12)
- # rum (35)
- # spacemacs (2)
- # specter (5)
- # test-check (6)
- # yada (52)
Hi —I'm looking for advice on how to implement a mixin that only allows a component to render after a specified delay. Something that I currently implement with the rum/local
plugin:
(rum/defcs my-component < (rum/local {:show? false})
{:did-mount (fn [{local-state :rum/local :as state}]
(go (async/<! (async/timeout 1000))
(swap! local-state assoc :show? true))
state)}
[{local-state :rum/local}]
(when (:show? @local-state)
[:div "My component"]))
I'd like to abstract this. But :wrap-render
does not have access to component state, so I'm not sure how to go about this.
(defn render-after [timeout]
{ :wrap-render
(fn [render-fn]
(fn [state]
(if (::show? state)
(render-fn state)
[nil state]))) })
And BTW, @tonsky, the server-side rendering works beautifully. I'm very happy with it on https://partsbox.io/ — the only minor nitpick is that I have to send the content twice for some pages (once in the server-rendered DOM and another time in the global page args, so that ClojureScript can render the same thing). But the performance benefits outweigh the drawbacks.
(defn now []
(.geTime (js/Date.)))
(defn render-after [timeout]
{ :did-mount
(fn [state]
(assoc state
::timer (let [comp (:rum/react-component state)]
(js/setTimeout #(rum/request-render comp) timeout))
::mount-ts (now)))
:will-unmount
(fn [state]
(js/clearTimeout (::timer state))
(dissoc state ::timer))
:wrap-render
(fn [render-fn]
(fn [state]
(if (>= (- (now) (::mount-ts state)) timeout)
(render-fn state)
[nil state]))) })
I'm scared of JavaScript, truth be told. I never know when it will blow up in my face.
Oh, and there is another nitpick: I think I'm losing quite a bit of performance because I'm passing anonymous functions as arguments to components, so rum/static
can't really do its work.
But I found that callbacks work really well and make for simple reusable components.
I also think that rum is under-appreciated. Reagent and Om get tons of publicity, while Rum gets almost none — in spite of a really solid server-side rendering story.
Rum is for the pros 😛 😎
(just kidding of course 😄)
@tonsky I'm slightly puzzled why :wrap-render
gets called before :did-mount
. I get two calls, one happens before :did-mount
.
it doesn’t solve problems for you in one-size-fits-all manner, but give you the tools to solve your specific problems in the best way
I think Reagent is a great starting point, actually — but once you start feeling limited, it's good to switch to Rum.
it might’ve been harder to make a mistake if they were called before-render
and after-render
Ok, so here's what I ended up with, in case anybody cares:
(defn render-after [timeout]
{:will-mount (fn [{react-component :rum/react-component :as state}]
(let [show (atom false)]
(go (async/<! (async/timeout timeout))
(reset! show true)
(rum/request-render react-component))
(assoc state ::show? show)))
:wrap-render (fn [render-fn]
(fn [state]
(if @(::show? state)
(render-fn state)
[nil state])))})
Another observation: there are tremendous advantages to quietly loading your entire application in the background, while the user is still on the landing page. As an example, all of my pricing and signup code is in the same app. This means no further waiting — so if you click on the "demo", only additional demo data needs to get loaded, the app is already loaded and parsed/compiled. It works really well.