I have a style question for you all, and I want to understand if there’s an underlying guiding principle to follow….
When rendering a component with zero arguments, but with local state (let), when do you return a rendering function (fn) versus just the raw hiccup syntax (vector of components)?
I should add that in re-frame code, many of those ‘let’ bindings are not actually local state (r/atom), but rather subscriptions, so that is subtly different but could make a big difference in the understanding of ‘local state’.
A local state necessitates form-2, form-3, or r/with-let.
So you cannot just return Hiccup, at all.
Unless you don't use that state in the component itself and pass it to children. But I myself wouldn't call that state "local".
Regarding re-frame - that's just not local state at all, it's global, by all accounts.
Ok, that’s what I was thinking. With re-frame, it’s not necessary to return the fn like it would be with an atom of local state.
Indeed.
@lucio I am using the lovely https://github.com/luciodale/fork library and facing a weird issue where while changing any character in an input field cursor moves to the end.
(defn- add-user-form [{:keys [values form-id handle-change handle-blur submitting? handle-submit]}]
[:form {:id form-id
:on-submit handle-submit}
[:div.flex.flex-col.gap-4
[:div.flex.max-w-lg.gap-4.items-center
[label/label {:html-for :name} "Name"]
[input/input {:id :name
:name "name"
:value (get values "name")
:on-change handle-change
:on-blur handle-blur}]]]])
(defn- add-client-comp []
[drawer/drawer {:shouldScaleBackground true}
[drawer/trigger {:asChild true}
[button/button "Add Client"]]
[drawer/content {:class "h-[60%]"}
[:div.w-full
[drawer/header
[drawer/title "New Client"]
[drawer/description "Just basic information about the user, you can update it later as well!"]]
[:hr.mb-10]
[:div.px-4
[fork/form {:id ::add-user-form
:initial-values {"name" "Hello"}
:path [::add-user-form]
:prevent-default? true
:clean-on-unmount? true
:on-submit #(js/console.log %)
:on-blur #(js/console.log %)}
add-user-form]]]]])
What am I doing wrong here?Just to make sure - are you using the latest version of Reagent?
No, I am on v1.1.1 🤔
The issue persists with reagent v1.2.0
How do you use add-client-comp?
[:div.w-full.flex.gap-2
[input/input {:class "bg-white max-w-64"
:type :text
:onChange (debounce
(fn [evt]
(reset! filter-string! (oget evt :target.value)))
500)
:placeholder "Search for a client"}]
[button/button {:class "ml-auto"
:variant :outline}
"Bulk Import"]
[add-client-comp]]
It's part of the bigger component. Pasted above a snippet from itThis is how the UI looks.
It seems as if some of the parent components is re-rendered when only the form itself should be, as described in this section: https://github.com/luciodale/fork?tab=readme-ov-file#can-i-go-anonymous
But that section doesn't cover your case.
Maybe you have a :key somewhere that forces the whole relevant component tree to be re-rendered?
https://gist.github.com/Samy-33/3acfa0157a17d526ddf9b270e50b85ce The whole file ^ As I believe the above snippet isn't that helpful.
Things like this are possible to debug with React DevTools, assuming you're using a compatible version of React. And if you don't, there's a way to install an older version of the extension.
In handle-change fn https://github.com/luciodale/fork/blob/master/src/fork/core.cljs#L133-L137, we update the state. Which is passed to the form-component https://github.com/luciodale/fork/blob/master/src/fork/reagent.cljs#L88-L90. Wouldn't that cause the re-render of the form component, when anything in the input changes? This will in turn reset the cursor position, if I am not wrong.
Also, rerender of the form component is caused by argv change. I believe that's pointing to the state change?
argv is probably what r/argv returns - i.e. the whole Hiccup vector, including all the arguments and the children.
> Wouldn't that cause the re-render of the form component, when anything in the input changes?
Maybe? Sorry, don't have a brain capacity at the moment to carefully check.
sorry to be late to the party but I’m not so much on clojurians… I think the problem lies in the drawer component.. that’s doing something that’s making the cursor jump.. usually there are props you can pass those components to prevent this problem..
I had a similar issue with a drawer component (Joy, MUI)
and the fix was to pass a disablePortal prop which does: The children will be under the DOM hierarchy of the parent component.
you get funky behaviours when the children are placed outside of your react tree
hope that helps
Thanks Lu. That does make sense. I'll try that and let you know
OFC man! 🙂
If on every input change, your logic is repeatedly writing the same old value into the current input value, instead of the new one, then you'll see that cursor behavior, iirc. Have you tried adding printlns inside the input handler to see what you're passing in?
I'll check this today..