Last active
March 28, 2024 01:57
-
-
Save awwx/fa44158661520ea68fc0742b3c905589 to your computer and use it in GitHub Desktop.
lifecycle on-mount/on-unmount that works with reactive values
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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