ClojureScript。重新渲染时重置 Reagent 中的原子

ClojureScript. Reset atom in Reagent when re-render occurs

我正在显示一组测验问题,我为每个问题分配了一个编号,以便在浏览器中显示时编号:

(defn questions-list
 []
  (let [counter (atom 0)]
    (fn []
      (into [:section]
           (for [question @(re-frame/subscribe [:questions])]
              [display-question (assoc question :counter (swap! counter inc))])))))

问题是,当有人在浏览器中编辑问题时(调用调度并更新 "app-db" 地图)组件被重新渲染,但原子 "counter" 逻辑上启动从最后一个数字开始,而不是从零开始。所以我需要重置原子,但我不知道在哪里。我尝试在匿名函数中使用 let 但这没有用。

在这种情况下,我将完全删除状态。我没有测试过这段代码,但你的想法在这里是势在必行的。您尝试执行的操作的功能版本类似于: 贫穷但无国籍:

(let [numbers (range 0 (count questions))
      indexed (map #(assoc (nth questions %) :index %) questions)]
  [:section
   (for [question indexed]
     [display-question question])])

但这很丑陋,而且 nth 效率低下。所以让我们尝试一个更好的。事实证明 map 可以接受多个集合作为参数。

(let [numbers (range 0 (count questions))
      indexed (map (fn [idx question] (assoc question :index idx)) questions)]
  [:section
   (for [question indexed]
     [display-question question])])

但更好的是,事实证明有一个内置函数正是用于此目的。我实际上会写什么:

[:section
 (doall
  (map-indexed
   (fn [idx question]
     [display-question (assoc question :index idx)])
   questions))]

注意:此代码的 None 实际上是 运行,因此您可能需要稍微调整一下才能运行。我建议您查看 ClojureDocs 中的所有函数,以确保您了解它们的作用。

如果您需要 counter 只是一个问题的索引,您可以改用这样的东西:

(defn questions-list
 []
  (let [questions @(re-frame/subscribe [:questions])
        n (count questions)]
    (fn []
      [:section
        [:ul
          (map-indexed (fn [idx question] ^{:key idx} [:li question]) questions)]])))

注意:这里我使用了[:li question],因为我假设question是某种文本。

此外,您可以避免计算此组件中问题的 count,而使用 layer 3 subscription:

(ns your-app.subs
  (:require
   [re-frame.core :as rf]))

;; other subscriptions...

(rf/reg-sub
 :questions-count
 (fn [_ _]
   [(rf/subscribe [:questions])])
 (fn [[questions] _]
   (count questions)))

然后在组件的 let 绑定中,您需要将 n (count questions) 替换为 n @(re-frame/subscribe [:questions-count])