Reputation: 4582
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
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