如何在重新框架中循环订阅的集合并将数据显示为列表项?

nil*_*ock 9 clojure clojurescript reagent re-frame

考虑以下使用幽灵,试剂和重构框架的clojurescript代码,外部React.js网格组件用作视图组件.

在db.cls中:

(def default-db
  {:cats [{:id 0 :data {:text "ROOT" :test 17} :prev nil :par nil}
          {:id 1 :data {:text "Objects" :test 27} :prev nil :par 0}
          {:id 2 :data {:text "Version" :test 37} :prev nil :par 1}
          {:id 3 :data {:text "X1" :test 47} :prev nil :par 2}]})
Run Code Online (Sandbox Code Playgroud)

在subs.cls中

(register-sub
  :cats
  (fn [db]
    (reaction
      (select [ALL :data] (t/tree-visitor (get @db :cats))))))
Run Code Online (Sandbox Code Playgroud)

选择结果:

[{:text "ROOT", :test 17} 
 {:text "Objects", :test 27} 
 {:text "Version", :test 37} 
 {:text "X1", :test 47}]
Run Code Online (Sandbox Code Playgroud)

在views.cls中

(defn categorymanager []
      (let [cats (re-frame/subscribe [:cats])]
         [:> Reactable.Table
             {:data (clj->js @cats)}]))
Run Code Online (Sandbox Code Playgroud)

上面的代码按预期工作.

我不想使用react.js组件显示数据,而是通过:cats向量中的每个映射,并在html ul/li中显示:text项.

我开始如下:

(defn categorymanager2 []
      (let [cats (re-frame/subscribe [:cats])]
         [:div
           [:ul
             (for [category @cats] 
;;--- How to continue here ?? ---
        )
        ))
Run Code Online (Sandbox Code Playgroud)

预期产量:

ROOT
Objects
Version
X1
Run Code Online (Sandbox Code Playgroud)

如何在重新框架中循环订阅的集合并将数据显示为列表项?(=标题问题).

Mik*_*son 30

首先,要明确为什么要使用key......

key当列表非常动态时 - 为列表中的每个项目提供a 非常有用 - 当定期添加和删除新列表项时,特别是如果该列表很长,并且正在列表顶部附近添加/删除项目.

keys可以带来巨大的性能提升,因为它们允许React更有效地重绘这些可更改的列表.或者,更准确地说,它允许React避免重绘具有与上次相同的密钥,并且没有改变的项目,并且只是简单地向上或向下洗牌.

其次,如果列表非常静态(它不会一直改变)或者如果没有与每个项目关联的唯一值,请清楚应该做什么...

完全不要使用:key.相反,使用into这样:

(defn categorymanager []
  (let [cats (re-frame/subscribe [:cats])]
    (fn []
      [:div
       (into [:ul] (map #(vector :li (:text %)) @cats))])))
Run Code Online (Sandbox Code Playgroud)

注意这里发生了什么.通过所提供的列表中map被折叠into[:ul]载体.在它的最后,没有列表在望.只是嵌套的矢量.

当您嵌入list打嗝时,您只会收到有关丢失钥匙的警告.上面没有嵌入list,只是vectors.

第三,如果你的清单真的很动态......

key为每个项目添加唯一(独特的兄弟姐妹).在给出的例子中,它:text本身就足够了key(我认为它是唯一的):

(defn categorymanager []
  (let [cats (re-frame/subscribe [:cats])]
    (fn []
      [:div
        [:ul  (map #(vector :li {:key (:text %)} (:text %)) @cats)]])))
Run Code Online (Sandbox Code Playgroud)

map将导致a list是第一个参数[:ul].当Reagent/React看到list它想要keys在每个项目上看到时(记住列表与Reagent打嗝中的向量不同)并且将向控制台打印警告keys将丢失.

所以我们需要在key每个项目中添加一个list.在上面的代码中,我们不是:key通过元数据添加(虽然你可以这样做,如果你想),而是我们提供key通过第一个参数(的[:li]),通常也携带样式数据.

最后 - 第1部分不要map-indexed按照另一个答案的建议使用.

key应该是与每个项目相关联的唯一值.附加一些arb整数没有任何用处 - 好吧,它确实摆脱了控制台中的警告,但你应该使用into上面的技术,如果这就是你想要的.

最后 - 第2部分在这种情况下map和之间没有区别for.

他们都导致了list.如果list有钥匙那么没有警告.但如果缺少钥匙,那么就会发出很多警告.但是如何创建列表并没有进入它.

所以,这个for版本与版本几乎相同map.有些人可能更喜欢它:

(defn categorymanager []
  (let [cats (re-frame/subscribe [:cats])]
    (fn []
      [:div
        [:ul  (for [i @cats] [:li {:key (:text i)} (:text i)])]])))
Run Code Online (Sandbox Code Playgroud)

也可以使用这样的元数据编写:

(defn categorymanager []
  (let [cats (re-frame/subscribe [:cats])]
    (fn []
      [:div
        [:ul  (for [i @cats] ^{:key (:text i)}[:li  (:text i)])]])))
Run Code Online (Sandbox Code Playgroud)

最后 - 第3部分

mapv由于这个问题是一个问题:https: //github.com/Day8/re-frame/wiki/Using-%5Bsquare-brackets%5D-instead-of-%28parentheses%29#appendix-2