-
-
Save jeans11/38fe1a66553546de531f0746dc8aae5c to your computer and use it in GitHub Desktop.
Helix + Refx + Datascript = ❤️
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 io.lokky.web-ui.core | |
(:require [helix.core :refer [defnc $]] | |
[helix.dom :as d] | |
[helix.hooks :as hooks] | |
[refx.alpha :as rf] | |
[datascript.core :as dts] | |
["react-dom/client" :as react-dom])) | |
;;---------------------------------------- | |
;; DATABASE | |
;;---------------------------------------- | |
;; Create a mutable reference to an empty immutable database. | |
;; dts-conn is just an atom | |
(defonce dts-conn (dts/create-conn)) | |
;; Instead transact in the event handler (because should be pure of side effect), the datacript transact happen here. | |
(rf/reg-fx | |
:dts-tx-data | |
(fn [data] | |
(dts/transact! dts-conn (if (vector? data) data [data])))) | |
;; input-fn for the reg-sub | |
(def sub-datascript (constantly dts-conn)) | |
;;---------------------------------------- | |
;; EVENTS AND SUBSCRIPTIONS | |
;;---------------------------------------- | |
(rf/reg-event-fx | |
:greeting/add-name | |
(fn [_ [_ name]] | |
;; Just return the tx-data handled by the reg-fx | |
{:dts-tx-data {:db/add -1 :greeting/name name})) | |
(rf/reg-sub | |
:greeting/names | |
;; The magic happens here! | |
;; sub-datascript always return the dts-conn | |
;; dts-conn is an atom so a valid input signal!!! | |
sub-datascript | |
;; /_\ Warning /_\ | |
;; dts-db is the immutable database inside the dts-conn | |
(fn [dts-db _] | |
(dts/q '[:find ?e ?n | |
:where [?e :greeting/name ?n]] | |
dts-db))) | |
;;---------------------------------------- | |
;; VIEWS | |
;;---------------------------------------- | |
(defnc greeting [{:keys [name]}] | |
(d/div "Hello, " (d/strong name) "!")) | |
(defnc greeting-input [{:keys [value on-change]}] | |
(d/div | |
(d/input {:value value :on-change on-change}) | |
(d/button {:on-click #(rf/dispatch [:greeting/add-name value])} "Add name"))) | |
(defnc greeting-list [] | |
(let [greeting-names (rf/use-sub [:greeting/names])] | |
(d/div | |
(d/h4 "Greeting list") | |
(for [[id value] greeting-names] | |
(d/div {:key id} | |
(d/span id) | |
(d/span value)))))) | |
(defnc greeting-editor [] | |
(let [[state set-state] (hooks/use-state {:name "World"})] | |
(d/div | |
($ greeting {:name (:name state)}) | |
($ greeting-input {:value (:name state) | |
:on-change #(set-state assoc :name (.. % -target -value))})))) | |
(defnc app [] | |
(d/div | |
(d/h1 "Welcome!") | |
($ greeting-editor) | |
($ greeting-list))) | |
(defonce root | |
(react-dom/createRoot | |
(.getElementById js/document "root"))) | |
(defn main [& _args] | |
(.render root ($ app))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment