Skip to content

Instantly share code, notes, and snippets.

@waterlink
Last active February 1, 2017 01:59
Show Gist options
  • Save waterlink/629ce057cd2aded7a206 to your computer and use it in GitHub Desktop.
Save waterlink/629ce057cd2aded7a206 to your computer and use it in GitHub Desktop.
Reagent with Redux?
;; My idea of hierarchical Redux
;; ------------
;; reducers
;; reducers for todos (todo list)
(defmulti todos-reducer (fn [state ty data] ty))
(defmethod todos-reducer :todo-add [state ty {:keys [title done]}]
(let [state (update-in state [:counter] inc)
id (:counter state)
todo (new-todo-state id title done) ;; this is (atom {.. todo .. + todo reducers})
state (append-child-state state todo)]
(assoc-in state [:todos id] todo)))
(defmethod todos-reducer :todo-del [state ty {:keys [id]}]
(let [todo (get-in state [:todos id])
state (remove-child-state state todo)]
(dissoc-in state [:todos id])))
;; .. and so on ..
(defmethod todos-reducer :default [state ty data] state)
;; reducers for single todo list
(defmulti todo-reducer (fn [state ty {:keys [id]}]
(if (-> (:id state) (= id))
ty
:default)))
(defmethod todo-reducer :todo-toggle [state ty data]
(update state :done not))
(defmethod todo-reducer :todo-update [state ty {:keys [title]}]
(assoc state :title title))
;; .. and so on ..
(defmethod todo-reducer :default [state ty data] state)
;; ------------
;; state
(defonce state-reducers [todos-reducer])
(defonce state-todo-reducers [todo-reducer])
(defonce state (atom {:counter 0
:todos (sorted-map)
:redux-reducers state-reducers
:redux-children (sorted-map)}))
(defn new-todo-state [id title done]
"creates new todo state with data and special :redux-* keys for houskeeping"
(atom {:id id :title title :done done
:redux-reducers state-todo-reducers
:redux-children (sorted-map)}))
(defn append-child-state [state child]
"appends new child state"
(assoc-in state [:redux-children (:id child)] child))
(defn remove-child-state [state child]
"removes existing child state"
(dissoc-in state [:redux-children (:id child)] child))
(defn redux [state ty data]
"applies state's own reducers to it using action [ty data]"
(let [reducers (:redux-reducers state)]
(reduce #(%2 %1 ty data) state reducers)))
(defn rec-redux [state ty data]
"applies redux to the state and to all of its children"
(do
(redux state ty data)
(when-let [children (:redux-children state)]
#(map #(dispatch-to! % ty data) (vals children)))))
(defn dispatch-to [state ty data]
(trampoline rec-redux state ty data))
(defn dispatch-to! [state ty data]
"dispatches an action to a specific state"
(swap! state dispatch-to ty data))
(defn dispatch! [ty data]
"dispatches an action to a root state"
(dispatch-to! state ty data))
;; My current understanding of idiomatic Redux
;; ------------
;; reducers
(defmulti reducer (fn [state ty data] ty))
(defmethod reducer :add-todo [state ty {:keys [title done]}]
(let [state (update-in state [:counter] inc)
id (:counter state)]
(assoc-in state [:todos id] {:id id :title title :done done})))
(defmethod reducer :toggle-todo [state ty {:keys [id]}]
(update-in state [:todos id :done] not))
(defmethod reducer :update-todo [state ty {;keys [id title]}]
(assoc-in state [:todos id :title] title))
;; .. and so on ..
(defmethod reducer :default [state ty data] state)
;; ------------
;; state
(defonce state (atom {:counter 0
:todos (sorted-map)}))
(defonce state-reducers [reducer])
(defn redux [state reducers ty data]
"redux is for calculating new state using action [ty data] from state by applying all reducers"
(reduce #(%2 %1 ty data) state reducers))
(defn dispatch! [ty data]
"dispatch is for generating new action [ty data]"
(swap! state redux state-reducers ty data))
; -------------
; components
(defn home []
;; yes, this is the only atom dereference
[:div [todolist (:todos @state)]])
(defn todolist [todos]
[:ul
(for [id (keys todos)]
^{:key id} [todolistitem (get todos id)])])
;; this one is irrelevant for the example
;; nor it and none of child components do not dereference any atoms at this point
(defn todolistitem [] ... )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment