Skip to content

Instantly share code, notes, and snippets.

@ashnur
Forked from frankiesardo/core.cljs
Created March 19, 2021 17:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ashnur/e0e336c7ad0d79f06ff5be63cc1f00b4 to your computer and use it in GitHub Desktop.
Save ashnur/e0e336c7ad0d79f06ff5be63cc1f00b4 to your computer and use it in GitHub Desktop.
stop.worry/love-js
(ns stop-worry.core
(:require ["react" :as react :rename {createElement $}]
["react-dom" :as dom]
[goog.object :as obj]
[cljs.core.async :as async]))
(extend-type object
ILookup
(-lookup
([o k] (obj/get o (name k)))
([o k not-found] (obj/get o (name k) not-found))))
(defonce app-atom
(atom {:parent
{:name "Dad"}
:children
[{:name "Alice"}
{:name "Bob"}
{:name "Charlie"}]}))
(defonce app-chan (async/chan))
(defn useAtom [a]
(let [[state update-state] (react/useState @a)]
(react/useEffect
(fn []
(add-watch a :use-atom
(fn [_ _ _ new-state]
(update-state new-state)))
#(remove-watch a :use-atom))
#js [a])
state))
(defmulti handle-event (fn [atom event-name & _args] event-name))
(defmethod handle-event ::rename [atom _ index name]
(swap! atom assoc-in [:children index :name] (apply str (shuffle name))))
(defn eq [a b]
(= (:state a) (:state b)))
(defn Child* [{:keys [chan state]}]
(let [{:keys [name index]} state]
(js/console.log "Rendering Child " name)
($ "div" nil
($ "h3" nil "I'm a child component")
($ "span" nil "My name is: " name
($ "button" #js {:onClick #(async/put! chan [::rename index name])} "Rename me!")))))
(def Child (react/memo Child* eq))
(defn Parent* [{:keys [chan 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 :chan chan :state (assoc child :index i)})))))
(def Parent (react/memo Parent* eq))
(defn App []
(let [state (useAtom app-atom)]
(react/useEffect
(fn []
(let [loop (async/go-loop []
(let [event (async/<! app-chan)]
(js/console.log "--- Event received ---")
(apply handle-event app-atom event))
(recur))]
#(async/close! loop)))
#js [])
(js/console.log "Rendering App")
($ "div" nil
($ "h1" nil "This is a sample app")
($ Parent #js {:chan app-chan :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