[英]clojurescript + reagent issue
我正在使用clojurescript和試劑制作一個簡單的網絡應用程序。 我想創建一個簡單的“tab”組件,它將包含(對於初學者)文本輸入組件。
該應用程序有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)))
問題是,當我切換標簽時,組件共享輸入字段的值 - 我在這里做錯了什么?
非常感謝你的幫助!
問題是你將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)]])))
我認為這里存在一些問題,因為您正在混合應用程序數據(狀態)和顯示邏輯數據(即DOM)。 如果你保持兩個不同的東西,即在一個原子中保持你的應用程序狀態,在另一個原子中保持與組件顯示相關的數據,那么事情可能會更清晰。
您的簡單選項卡組件不需要了解選項卡狀態。 它只需要知道應用程序狀態,即通過atom-input輸入/存儲的值。 因此,不是傳遞索引,而是將它傳遞給您想要使用的原子。 這將需要一些更高級別的邏輯來確定呼叫。 例如,如果你有很多標簽,你可能會有類似的東西
(condp = @index
0 [simple-tab tab0-atom]
1 [simple-tab tab1-atom]
...
n [simple-tab tabn-atom])
或者你可以修改simple-tab,以便傳入的值,即索引值被用作app-state的一個鍵 - 我認為游標最簡單,即
(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]))
您正在使用form-2組件,即返回函數的組件。
更多細節: https : //github.com/Day8/re-frame/wiki/Creating-Reagent-Components#form-2--a-function-returning-a-function
這樣做時,只調用返回的函數,因此你的atom-inputs共享同一個原子。
此外,您應該在內部函數中使用相同的參數
(defn simple-tab [index]
(let [pg-index (atom 1)
a (atom {})]
(fn [index]
[:div
[:h4 (str "index: " @index)]
[atom-input a @index]])))
在你的情況下,你傳遞一個原子,所以這並不重要,但如果你忘了這個,你將來可能會有錯誤。
關於更廣泛的架構,我建議你使用一個全局原子。 嘗試在這個原子中盡可能多地保持狀態並避免組件本地狀態,這樣更容易推理。
您還可以將選項卡命名為:product:users,並使用multimethod根據所選標簽呈現正確的選項卡。 這樣更容易閱讀,並且將來更容易添加新標簽。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.