Skip to content

Instantly share code, notes, and snippets.

@awwx
Last active March 28, 2024 01:57
Show Gist options
  • Save awwx/fa44158661520ea68fc0742b3c905589 to your computer and use it in GitHub Desktop.
Save awwx/fa44158661520ea68fc0742b3c905589 to your computer and use it in GitHub Desktop.
lifecycle on-mount/on-unmount that works with reactive values
(ns lifecycle
(:require
[missionary.core :as m]
[hyperfiddle.electric :as e]
[hyperfiddle.electric-dom2 :as dom]))
;; Electric doesn't guarantee, in general, that reactive updates
;; will be performed in a particular order... but this specific
;; recipe is believed to be OK due to details of Electric's
;; execution model.
;;
;; https://clojurians.slack.com/archives/C7Q9GSHFV/p1711370410453149?thread_ts=1711327204.210359&cid=C7Q9GSHFV
(e/defn To-Atom [x]
(let [!x (atom ::never-seen)]
(reset! !x x)
!x))
(defn mlifecycle [!mount !unmount]
(m/observe
(fn [emit!]
(when-let [callback @!mount] (callback))
;; Electric requires flows to have an initial value
(emit! nil)
(fn []
(when-let [callback @!unmount] (callback))))))
(e/defn Lifecycle [mount unmount]
(let [!mount (To-Atom. mount)
!unmount (To-Atom. unmount)]
(new (mlifecycle !mount !unmount))))
(e/defn Main [ring-request]
(e/client
(let [!state (atom {:k :a, :show true})
state (e/watch !state)]
(binding [dom/node js/document.body]
;; some buttons to change the state
(dom/div
(dom/text "set k: ")
(e/for [id [:a :b :c]]
(dom/button
(dom/props {:id (name id)})
(dom/text (name id))
(dom/on! "click"
(fn [_]
(println "--- click" id)
(swap! !state assoc :k id))))
(dom/text " ")))
;; toggle show
(dom/div
(dom/button
(dom/text (if (:show state) "Hide" "Show"))
(dom/on! "click"
(fn [_]
(println "--- click show/hide")
(swap! !state update :show not)))))
;; display the state for convenience
(dom/pre (dom/text "state: " (pr-str state)))
(when (:show state)
(let [k (:k state)]
(dom/div
(dom/text "child: " (name k))
(println "mount child 1 (nonreactive)")
(println "mount child 2 (broken reactive)" k)
(e/on-unmount
(fn [] (println "e/on-unmount child 1 (nonreactive)")))
(e/on-unmount
(fn [] (println "e/on-unmount child 2 (broken reactive)" k)))
(Lifecycle.
(fn [] (println "lifecycle mount (reactive ok)" k))
(fn [] (println "lifecycle unmount (reactive ok)" k))))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment