ClojureScript. Нулиране на атом в Reagent, когато възникне повторно изобразяване

Показвам набор от въпроси за тест тест и присвоявам номер на всеки въпрос, само за да ги номерирам, когато се показват в браузъра:

(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" се актуализира), компонентът се изобразява отново, но атомният "брояч" логично започва от последното число, а не от нула . Така че трябва да нулирам атома, но не знам къде. Опитах с let вътре в анонимната функция, но това не проработи.


person aarkerio    schedule 30.12.2019    source източник


Отговори (2)


В този случай просто бих премахнал държавата изцяло. Не съм тествал този код, но вашето мислене е наложително тук. Функционалната версия на това, което се опитвате да направите, е нещо от рода на: Беден, но без гражданство:

(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))]

Забележка: Нито един от този код всъщност не е стартиран, така че може да се наложи да го промените малко, преди да заработи. Бих препоръчал да потърсите всички функции в ClojureDocs, за да сте сигурни, че разбирате какво правят.

person Walton Hoops    schedule 31.12.2019

Ако имате нужда 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 за въпроси в този компонент и да го направите с абонамент за слой 3:

(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]).

person jackdbd    schedule 22.06.2020