Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
reducer-context.core
(ns reducer-context.core
(:require ["react" :as react :rename {createElement $}]
["react-dom" :as dom]
[goog.object :as obj]))
(extend-type object
ILookup
(-lookup
([o k] (obj/get o (name k)))
([o k not-found] (obj/get o (name k) not-found))))
(def initial-state
{:parent
{:name "Dad"}
:children
[{:name "Alice"}
{:name "Bob"}
{:name "Charlie"}]})
(defmulti reducer (fn [state {:keys [type payload] :as action}] type))
(defmethod reducer ::rename [state {{:keys [index]} :payload}]
(update-in state [:children index :name] #(apply str (shuffle %))))
(defn reducer* [state action] (reducer state action))
(defn eq [a b]
(= (:state a) (:state b)))
(def DispatchContext (react/createContext))
(defn Child* [{:keys [state]}]
(let [{:keys [name index]} state
dispatch! (react/useContext DispatchContext)
action {:type ::rename :payload {:index index}}]
(js/console.log "Rendering Child " name)
($ "div" nil
($ "h3" nil "I'm a child component")
($ "span" nil "My name is: " name
($ "button" #js {:onClick #(dispatch! action)} "Rename me!")))))
(def Child (react/memo Child* eq))
(defn Parent* [{:keys [state]}]
(let [{:keys [parent children]} state]
(js/console.log "Rendering Parent")
($ "div" nil
($ "h2" nil "I'm the parent component")
($ "div" nil "My name is: " (get parent :name))
(for [[i child] (map-indexed vector children)]
($ Child #js {:key i :state (assoc child :index i)})))))
(def Parent (react/memo Parent* eq))
(defn App []
(let [[state dispatch!] (react/useReducer reducer* initial-state)]
($ DispatchContext.Provider #js {:value dispatch!}
($ Parent #js {:state state}))))
(defn start []
(dom/render ($ App) (js/document.getElementById "app")))
(defn ^:export init []
(start))
(defn stop []
(js/console.log "stop"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment