Skip to content

Instantly share code, notes, and snippets.

@arnaudbos
Last active August 29, 2015 14:16
Show Gist options
  • Select an option

  • Save arnaudbos/8f4d53020d941af5a5cb to your computer and use it in GitHub Desktop.

Select an option

Save arnaudbos/8f4d53020d941af5a5cb to your computer and use it in GitHub Desktop.
should-component-update with vector
(ns todomvc
(:require [reagent.core :as reagent :refer [atom]]))
(defonce todos (atom (sorted-map)))
(defonce counter (atom 0))
(defn add-todo [text]
(let [id (swap! counter inc)]
(swap! todos assoc id {:id id :title text :done false})))
(defn toggle [id] (swap! todos update-in [id :done] not))
(defn save [id title] (swap! todos assoc-in [id :title] title))
(defn delete [id] (swap! todos dissoc id))
(defn mmap [m f a] (->> m (f a) (into (empty m))))
(defn complete-all [v] (swap! todos mmap map #(assoc-in % [1 :done] v)))
(defn clear-done [] (swap! todos mmap remove #(get-in % [1 :done])))
(defonce init (do
(add-todo "Rename Cloact to Reagent")
(add-todo "Add undo demo")
(add-todo "Make all rendering async")
(add-todo "Allow any arguments to component functions")
(complete-all true)))
(defn todo-input [{:keys [title on-save on-stop]}]
(let [val (atom title)
stop #(do (reset! val "")
(if on-stop (on-stop)))
save #(let [v (-> @val str clojure.string/trim)]
(if-not (empty? v) (on-save v))
(stop))]
(fn [props]
[:input (merge props
{:type "text" :value @val :on-blur save
:on-change #(reset! val (-> % .-target .-value))
:on-key-down #(case (.-which %)
13 (save)
27 (stop)
nil)})])))
(def todo-edit (with-meta todo-input
{:component-did-mount #(.focus (reagent/dom-node %))}))
(defn todo-stats [{:keys [filt active done]}]
(let [props-for (fn [name]
{:class (if (= name @filt) "selected")
:on-click #(reset! filt name)})]
[:div
[:span#todo-count
[:strong active] " " (case active 1 "item" "items") " left"]
[:ul#filters
[:li [:a (props-for :all) "All"]]
[:li [:a (props-for :active) "Active"]]
[:li [:a (props-for :done) "Completed"]]]
(when (pos? done)
[:button#clear-completed {:on-click clear-done}
"Clear completed " done])]))
(defn -todo-item []
(let [editing (atom false)]
(fn [{:keys [id done title]}]
(.log js/console "todo-item rendering")
(.log js/console (str id " " done " " title))
[:li {:class (str (if done "completed ")
(if @editing "editing"))}
[:div.view
[:input.toggle {:type "checkbox" :checked done
:on-change #(toggle id)}]
[:label {:on-double-click #(reset! editing true)} title]
[:button.destroy {:on-click #(delete id)}]]
(when @editing
[todo-edit {:class "edit" :title title
:on-save #(save id %)
:on-stop #(reset! editing false)}])])))
(def todo-item
(with-meta -todo-item
{
:component-will-mount (fn [this]
(.log js/console "-todo-item will-mount")
)
:component-did-mount (fn [this]
(.log js/console "-todo-item did-mount")
)
:component-will-update (fn [this]
(.log js/console "-todo-item will-update")
)
:component-did-update (fn [this]
(.log js/console "-todo-item did-update")
)
:component-will-unmount (fn [this]
(.log js/console "-todo-item will-unmount")
)
:should-component-update (fn [this old-argv new-argv]
(not= old-argv new-argv))
}))
(defn -todo-app [props]
(let [filt (atom :all)]
(fn []
(.log js/console "todo-app rendering")
(let [items (vals @todos)
done (->> items (filter :done) count)
active (- (count items) done)]
[:div
[:section#todoapp
[:header#header
[:h1 "todos"]
[todo-input {:id "new-todo"
:placeholder "What needs to be done?"
:on-save add-todo}]]
(when (-> items count pos?)
[:div
[:section#main
[:input#toggle-all {:type "checkbox" :checked (zero? active)
:on-change #(complete-all (pos? active))}]
[:label {:for "toggle-all"} "Mark all as complete"]
[:ul#todo-list
(comment for [todo (filter (case @filt
:active (complement :done)
:done :done
:all identity) items)]
^{:key (:id todo)} [todo-item todo])
(map-indexed
(fn [i todo]
^{:key (:id todo)} [todo-item (assoc todo :path [i])])
(filter (case @filt
:active (complement :done)
:done :done
:all identity) items))
]]
[:footer#footer
[todo-stats {:active active :done done :filt filt}]]])]
[:footer#info
[:p "Double-click to edit a todo"]]]))))
(def todo-app
(with-meta -todo-app
{
:component-will-mount (fn [this]
(.log js/console "-todo-app will-mount")
)
:component-did-mount (fn [this]
(.log js/console "-todo-app did-mount")
)
:component-will-update (fn [this]
(.log js/console "-todo-app will-update")
)
:component-did-update (fn [this]
(.log js/console "-todo-app did-udpate")
)
:component-will-unmount (fn [this]
(.log js/console "-todo-app will-unmount")
)
}))
(defn ^:export run []
(reagent/render [todo-app]
(js/document.getElementById "app")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment