clojurescriptreagentre-frame

ClojureScript. Reset atom in Reagent when re-render occurs


I'm displaying a set of questions for a quiz test and I'm assigning a number to each question just to number them when they are shown in the browser:

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

The problem is that when someone edits a question in the browser (and the dispatch is called and the "app-db" map is updated) the component is re-rendered but the atom "counter" logically starts from the last number not from zero. So I need to reset the atom but I don't know where. I tried with a let inside the anonymous function but that didn't work.


Solution

  • In this case I'd just remove the state entirely. I haven't tested this code, but your thinking imperatively here. The functional version of what your trying to do is something along the lines of: Poor but stateless:

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

    but this is ugly, and nth is inefficient. So lets try one better. Turns out map can take more than one collection as it's argument.

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

    But even better, turns out there is a built in function for exactly this. What I'd actually write:

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

    Note: None of this code has actually been run, so you might have to tweak it a bit before it works. I'd recommend looking up all of the functions in ClojureDocs to make sure you understand what they do.