为什么不能在 let 中定义试剂成分的状态?

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

假设我们有一个用 hiccup 语法定义的文本文本区域。

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

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

假设我们想要在我们的文档中有多个文本区域副本,每个副本都有不同的状态。然后,我们必须将当前命名空间中所有人当前可用的状态移动到词法范围的符号中。类似于:

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

但就目前而言,这段代码不起作用。无论用户输入什么,文本字段总是以空结束。这是为什么?以及如何将我的状态包含在每个组件的词法范围内?

这个问题的答案可以在 re-frame documentation 中找到,它描述了通常在试剂项目中找到的不同形式的组件。它指出,为了为 per-component 状态提供一个持久的词法作用域,必须编写一个 returns 另一个渲染函数的函数;否则,每次试剂尝试 re-render 组件时,都会重新定义状态原子。所以对于给定的组件:

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

这样,试剂在重绘组件时调用的函数就是内部匿名函数。定义词法作用域的 let 不会是 re-run.

此答案的所有功劳归功于 clojurians slack 上的用户 mccraigmccraig。