This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-27
Channels
- # announcements (1)
- # aws (17)
- # babashka (2)
- # beginners (14)
- # calva (1)
- # cider (16)
- # clara (1)
- # clj-kondo (68)
- # cljdoc (2)
- # clojure (51)
- # clojure-dev (1)
- # clojure-italy (2)
- # clojure-spec (1)
- # clojure-uk (19)
- # clojurescript (34)
- # cursive (4)
- # fulcro (1)
- # heroku (3)
- # leiningen (36)
- # lumo (28)
- # music (2)
- # off-topic (16)
- # reagent (22)
- # specter (7)
- # sql (7)
is there a clever way to recursively call parent component functions that haven't yet been defined? for example, component-a
expects component-b
to be defined, while component-b
expects component-a
to be defined:
(defn component-b [children]
(if (coll? children)
; component-a not yet defined, compile error
[:li [component-a children]]
[:li (str "leaf: " children)]))
(defn component-a [tree]
(into [:ul]
(map (fn [[k v]] [component-b v]) tree)))
Hi, I am trying to use react-spring within reagent and I am not yet very familiar with using React components. How should I rewrite the first example into Reagent: https://www.react-spring.io/docs/props/spring ??
In the end, I got the following wrapper working, but not sure whether this is done in the most useful way:
(defn spring
[attr component input-fn]
[:> rspring/Spring attr
(fn [props] (-> #(-> % (js->clj :keywordize-keys true)
component)
r/reactify-component
(r/create-element (clj->js (input-fn props)))))])
Used as
[spring {:from {:opacity 0}
:to {:opacity 1}}
(fn [props]
[:div props "Hello world!"])
(fn [props] {:style props})]
I am probably doing something wrong since it runs very slowly on larger components. In each animation frame, the entire dom subtree is completely replaced.
1. You're doing too much JS<->CLJS churning. Just don't do that at all in your code. If you really have to change something, prefer JS interop or cljs-bean
.
2. Don't call components directly as functions and don't create unnecessary lambdas.
3. react-spring
itself says here https://www.react-spring.io/docs/props/spring: "Of course the only properties that the browser can animate relatively cheaply are composite properties (opacity, transform), so you might want to watch out for that."
Here's a simplified version of your code that also works a bit faster:
(defn spring [attr component]
[:> rspring/Spring attr
(fn [props]
(r/create-element
(r/reactify-component component)
props))])
(defn unit [{:keys [left]}]
[:div.unit {:on-click #(rf/dispatch [:update-position])
:style {:top 100
:left left}}
[:div.title "Title of unit"]
[:div.content
[:div "Click this unit to move it."]
[:img {:src "/img/Clojure_logo.png"
:width 300
:height 300}]]])
(defn main-panel []
(let [position @(rf/subscribe [:position])]
[spring {:to {:left (if (= position :left)
100
500)}}
unit]))
Not sure whether it's relevant to what you're doing and to Spring in general, but you may be interested in the FLIP approach: https://aerotwist.com/blog/flip-your-animations/
Thanks for the simplification, it now runs much better, in particular, it correctly updates only the style instead of replacing the entire subtree on every animation frame.
One problem left in my main code is that at the beginning of the animation, the entire component subtree is completely replaced which makes the animation slower. The reason is that I have a component data in a map obtained by a subscription, and whenever these data are changed, we have a new component function. (The second paramater for spring is (partial component subscription-data).)
Would it help to move the subscription inside the component?
It seemed to help. So basically it is not good to use partial in components because any change in function parameters will cause rerendering of the entire subtree?
AFAIK providing functions will make React rerender the component since the function will always be created right where it's defined, and even if you don't change anything, the new function will not be identical to the old one.
After reading these links, you will probably know more than I remember. đ https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md https://github.com/reagent-project/reagent/blob/master/doc/WhenDoComponentsUpdate.md
And this one: https://github.com/day8/re-frame/blob/master/docs/Performance-Problems.md
thanks for the links, will take a look
currently, we are not using the power of subscriptions enought and a lot of logic is moved into views which is not ideal, so I plan to improve subscriptions quite a lot in future
Yeah, you definitely want to move as much data churning and logic into subscriptions as possible, but still within reason. You also may want to use subscription signals (subs that feed values to other subs) and maybe even raw subs. There's a lot of small things that are definitely worth knowing.