Thereβs a really nice tutorial on framer-motion (for React) at https://www.youtube.com/playlist?list=PL4cUxeGkcC9iHDnQfTHEVVceOEBsOf07i
framer-motion is pretty powerful but seems to require to use it at the bottom of the component hierarchy (i.e. motion implementation of html tags like motion.div, motion.button etc)
I did find that at least for simple things so far, can wrap a reagent component into a motion.div
and the animate of the motion.div animates the reagent component.
Hello, got a quick question. I've been learning re-frame lately and came across a scenario in my app where I want to call .focus
on an html element that only appears in the dom after an event (registered with reg-event-fx) is handled.
I made the call to focus the element an event with reg-event-fx
and used a dispatch
effect in the causal event with the ^:flush-dom
metadata on the event vector to make sure the element is rendered before .focus is called. If it weren't for needing that flush though, I would just use reg-fx
. Is there no way to flush the dom before an effect registered with reg-fx
is run?
Here's the code. If it weren't for needing to make sure the dom was rendered before ::focus-html-element
, I would just use reg-fx
to register it, because I'm not changing the db or returning any effects. Just wondering if this is idiomatic I guess.
To avoid complications, you could perhaps use the auto-focus
attribute?
(defn view
[]
[:input {:type "text" :id "fname" :auto-focus true])
This only works once, when the widget is first rendered which may not give enough control, but it sure is simpler.Ah, thanks! I was not aware of this.
Also I think it doesn't work in Safari which is sadly IE of the current time π
If that doesn't give you enough control, you could create an effect which hooks into Reagent's after-render
https://github.com/reagent-project/reagent/blob/master/src/reagent/core.cljs#L340-L346
(reg-fx
:focus-html-element
(fn [element-id]
(reagent/after-render #(some-> js/document (.getElementById element-id) .focus)))
This gave me the control+simplicity I was looking for. π
Note the use of some->
to avoid any weird corner cases
@brandon.ringe I tend to leave re-frame out of that type of very view specific logic / close to DOM and use Reagent Form-3 components for that. Something like this should do the trick:
(defn focus-input []
(let [ref (atom nil)]
(r/create-class
{:component-did-mount
(fn [_]
(.focus @ref))
:reagent-render
(fn [_]
[:input {:ref #(reset! ref %)}])})))
Interesting, this looks possibly more efficient than the .getElementById
method since it avoids the lookup. Maybe not significant, but still.
π
Thanks for all the info! Great solutions
@brandon.ringe Hereβs one more that should work - if you want to use it and have trouble let me know and Iβll double check (writing code on my phone is not always a good idea)
[:input {:ref #(when % (.focus %))}]
Thanks