Rovanion
Rovanion

Reputation: 4582

Why is it not possible to define the state of a reagent component in a let?

Say that we have a text text area defined in hiccup syntax.

(def written-text (reagent/atom ""))

(defn text-area []
    [:textarea
     {:value     @written-text
      :on-change #(reset! written-text (-> % .-target .-value))
      :on-click  #(println @written-text)}])

Say that we want to have multiple copies of text-area in our document, each with different state in them. Then we'll have to move the state currently available to all in the current namespace into a lexically scoped symbol. Something like:

(defn text-area []
  (let [written-text (reagent/atom "")]
    [:textarea
     {:value     @written-text
      :on-change #(reset! written-text (-> % .-target .-value))
      :on-click  #(println @written-text)}]))

But as it stands this code doesn't work. The text field always ends up empty no matter what the user inputs. Why is that? And how do I enclose my state in a per component lexical scope?

Upvotes: 0

Views: 196

Answers (1)

Rovanion
Rovanion

Reputation: 4582

The answer to this issue can be found in the re-frame documentation which describes the different forms of components that are normally found in a reagent project. It states that in order to provide a persistent lexical scope for the per-component state to live in, one must write a function which returns another rendering function; else the state atom will be redefined every time reagent tries to re-render the component. So for the given component:

(defn text-area []
  (let [written-text (atom "")]
    (fn []                                       
      [:textarea
        {:value     @written-text
         :on-change #(reset! written-text (-> % .-target .-value))}])))

This way, the function called by reagent when it wishes to redraw the component is the internal, anonymous, function. The let which defines the lexical scope won't be re-run.

All credit for this answer goes to user mccraigmccraig on the clojurians slack.

Upvotes: 1

Related Questions