Hey! Beginner question. When working with Reagent and Shadow-CLJS, I'd like to save my .cljs
file and show changes I've made to my components. Do I have to re-mount my top-level component to achieve this?
Reading this now: https://cljdoc.org/d/reagent/reagent/1.0.0-alpha2/doc/tutorials/when-do-components-update- Seems like I could change a ratom on page loads, and dereference it in a component. That feels a bit hacky, though.
Just call render after changes are loaded. I think easiest way is to just call it from your core ns top-level: https://github.com/reagent-project/reagent/blob/master/examples/react-sortable-hoc/src/example/core.cljs#L85-L88 (your core ns depends on all other ns, so it will be re-evaluated after any changes) but you could also use Shadow-cljs :dev/after-load
hook.
What is the state of reagent 1.0? Is there anything more to test?
Thanks! Have you run into performance problems re-mounting your entire application on each file change?
No. It doesn't cost much, render calls should be quite cheap and if components don't change, React doesn't need to do any DOM operations.
> if components don't change, React doesn't need to do any DOM Huh, it's that smart. I wasn't expecting to reagent/react to give me the same performance guarantees when re-mounting the entire application. Thanks for the help :thumbsup:
Hi again!
I want to fill a textarea from stored state when I initialize a component, but just on creation. Reading the https://cljdoc.org/d/reagent/reagent/1.0.0-alpha2/doc/tutorials/creating-reagent-components#the-three-ways, it seems that I need to move from a form-1 component to a form-3 component to be able to provide an initial value.
I've written some code that does not fill the initial value (I want to fill the initial value). It seems that I'm misunderstanding what this
is in :get-initial-state (fn [this] ,,,)
.
I'd appreciate an extra pair of eyes on my problem. Thanks!
(defn my-textarea-1 []
[:textarea {:id "myedit"
:onBlur (fn [event]
(save-event! event)
(let [text (-> event .-target .-value)]
(swap! r assoc :text text)))}])
(defn my-textarea-2 []
(r/create-class
{:display-name "my-textarea-2"
:get-initial-state (fn [this]
(save-this! this)
(when-let [text (:text @r)]
(set! (.-value this) text))
:loaded)
:reagent-render (fn []
[:textarea {:id "myedit"
:onBlur (fn [event]
(let [text (-> event .-target .-value)]
(swap! r assoc :text text)))}])}))
save-event!
and save-this!
are for debugging purposes, feel free to ignore them.
I found a way to avoid using a form-3 component after all: react supports providing a defaultValue
to textareas for just this purpose.
New form-1 component:
(defn my-textarea-1 []
[:textarea {:id "myedit"
:onBlur (fn [event]
(save-event! event)
(let [text (-> event .-target .-value)]
(swap! r assoc :text text)))
:defaultValue (:text @r)}])
I'm still curious about my initial error.Got it working! 🎉 :duckie:
• this refers to a react object, not the dom node
• I can use reagent.dom/dom-node
to get a dom node for a react element
• :get-initial-state
is called before the component is mounted, so there is no DOM node to modify.
• :component-did-mount
, however, is called after the component mounts. We can use that one!
Here's my (now working) form-3 component:
(defn my-textarea-2 [id]
(reagent/create-class
{:display-name "my-textarea-2"
:component-did-mount (fn [this]
(save-this! this)
(when-let [text (:text @r)]
(set! (.-value (reagent.dom/dom-node this))
text))
:loaded)
:reagent-render (fn []
[:textarea {:id id
:onBlur (fn [event]
(let [text (-> event .-target .-value)]
(swap! r assoc :text text)))}])}))
@teodorlu preferably, in React land, you should avoid getting DOM nodes like that and setting attributes on them outside of React. Sometimes of course, it's not possible, but it seems in your case, you could just set the :value
of the text area and avoid a whole lot of that manual DOM manipulation
@victorbjelkholm429
If I were to set the :value
directly, I'd have to handle another bit of state: I'd have to use :onChange
in addition to :onBlur
, and store what is written in the textarea at any time externally, in addition to the value after the blur.
Would you still prefer setting the :value
?
I see the argument for not editing the DOM nodes behind react in general. In this case, I don't see any specific arguments against editing, but I might be missing something.
(if we ignore the :defaultValue
solution, wich bypasses this problem entirely)
Did you do some survey to know what the users think? Or some kind of cost-benefits? I like having functional component only with :f>
but I ignore the consequence.
@teodorlu I'd go with value + onChange, form-1 component and no direct DOM manipulation. That to me feels the simplest and easiest. The value + onChange is a pretty common pattern. In React world they call components like this "controlled". https://reactjs.org/docs/forms.html#controlled-components
Thanks for the link to the react docs. It was nice to get a bit of extra context.
Perhaps the argument for "controlled components" is that you'll probably need to pipe in the text from somewhere else at some point regardless, and then it's just simpler to control that state in a single place? I'm trying to collect a bunch of textareas now, and I'm finding that not using controlled components might become more confusing than anything else.