3

我正在使用 clojurescript 和试剂开发一个简单的网络应用程序。我想创建一个简单的“选项卡”组件,它将包含(对于初学者)一个文本输入组件。

该应用程序有 2 个选项卡,用户可以选择一个选项卡,我想“保留”这两个选项卡中的每个选项卡中的值。

这是代码:

(defn atom-input [value]
  [:input {:type "text"
           :value @value
           :on-change #(reset! value (-> % .-target .-value))}])

(defn simple-tab [index]
  (let [pg-index (atom 1)
        a (atom 0)]
    (fn []
    [:div
     [:h4 (str "index: " @index)]
     [atom-input a]])))

(defn main-page []
  (let [index (atom 0)]
    [:div.container
     [:div.row
      [:button {:on-click (fn [] (reset! index 0))} "select tab 1"]
      [:button {:on-click (fn [] (reset! index 1))} "select tab 2"]]
     [:div.row
      [simple-tab index]]]))

(defn ^:export run []
  (reagent/render-component
   (fn [] [main-page])
   (.-body js/document)))

问题是当我切换选项卡时,组件共享输入字段的值 - 我在这里做错了什么?

非常感谢你的帮助!

4

3 回答 3

2

问题是您正在传递a (atom 0)atom-input控件:[atom-input a]. 这导致您的选项卡之间共享相同的原子值。

如果您不想共享该值,则需要更改a为 map:a (atom {})并将地图和索引传递给atom-input,例如:

(defn atom-input [value index]
  [:input {:type "text"
           :value (or (get @value index) "")
           :on-change #(swap! value assoc index (-> % .-target .-value))}])

(defn simple-tab [index]
  (let [pg-index (atom 1)
        a (atom {})]
    (fn []
      [:div
       [:h4 (str "index: " @index)]
       [atom-input a @index]])))

恕我直言,更好的方法是使用光标,这样您就不需要将索引和整个地图传递给atom-input,例如:

(defn atom-input [value]
  [:input {:type "text"
           :value (or @value "")
           :on-change #(reset! value (-> % .-target .-value))}])

(defn simple-tab [index]
  (let [pg-index (atom 1)
        a (atom {})]
    (fn []
      [:div
       [:h4 (str "index: " @index)]
       [atom-input (reagent/cursor [@index] a)]])))
于 2015-01-06T14:39:51.053 回答
2

我认为这里有几个问题,因为您正在混淆应用程序数据(状态)和显示逻辑数据(即 DOM)。如果您保持两件事不同,即在一个原子中维护您的应用程序状态,在另一个原子中维护与组件显示相关的数据,那么事情可能会更清晰一些。

您的 simple-tab 组件不需要知道任何有关选项卡状态的信息。它只需要了解应用程序状态,即通过 atom-input 输入/存储的值。因此,与其传递索引,不如传递你希望它使用的原子。这将需要一些更高级别的逻辑来确定调用。例如,如果您有许多选项卡,您可能会有类似

(condp = @index
  0 [simple-tab tab0-atom]
  1 [simple-tab tab1-atom]
  ...
  n [simple-tab tabn-atom])

或者您可以修改简单选项卡,以便将传入的值(即索引值)用作进入应用程序状态的键 - 我认为游标最简单,即

(def app-state (r/atom {:tabs {0 nil 1 nil}}})

(defn simple-tab [index]
  (let [val-cur (r/cursor app-state [:tabs index])]
    [atom-input val-cur]))
于 2015-10-07T00:53:37.997 回答
0

您正在使用 form-2 组件,即返回函数的组件。

更多详细信息:https ://github.com/Day8/re-frame/wiki/Creating-Reagent-Components#form-2--a-function-returning-a-function

这样做时,仅调用返回的函数,因此您的 atom-inputs 共享相同的 atom。

此外,您应该在内部函数中使用相同的参数

 (defn simple-tab [index]
      (let [pg-index (atom 1)
            a (atom {})]
        (fn [index]
          [:div
           [:h4 (str "index: " @index)]
           [atom-input a @index]])))

在您的情况下,您正在传递一个原子,因此这并不重要,但是如果您忘记了这一点,将来可能会出错。

关于更广泛的架构,我建议您使用单个全局原子。尝试在这个原子中拥有尽可能多的状态并避免组件本地状态,这样更容易推理。

您还可以将选项卡命名为 :product :users 并使用多种方法根据所选选项卡呈现正确的选项卡。这更容易阅读,并且将来更容易添加新标签。

于 2017-02-19T15:16:54.447 回答