Fulcro's compelling features are enabled by persistent data structures being first-class in the language.
Person p = new Person();
doSomethingOnAnotherThread(p);
p.fumble(); // Did p change? Race condition?
Person p = new Person();
doSomethingOnAnotherThread(p);
Person q = p.fumble(); // p unchanged, q could be different
Complete snapshot of application state → function → screen "looks right"
Like 2D game: redraw screen based on "state of the world"
Imperative Problems:
Pure Rendering Solution:
(def state {:items [{:id :a :checked? true} {:id :b :checked? false}]})
;; Check-all state is computed
(let [all-checked (every? :checked? (get state :items))]
(dom/input {:checked all-checked}))
;; State changes create new world
(def next-state (assoc-in state [:items 0 :checked?] false))
Benefits:
Instead of /person/3
, say:
"Person 3's name, age, and billing info, but only billing zip code"
[person: age? name?] → [billing info: zip?]
'(change-person {:id 3 :age 44})
Key insight: Encode as data structure, process locally AND transmit over wire
The client-side database is a persistent map representing a graph:
:person/id
, :account/email
){:person/id {4 {:person/id 4 :person/name "Joe"}}}
Definition: Tuples [TABLE ID]
that uniquely identify graph nodes
Example: [:person/id 4]
Usage:
(update-in state-db [:person/id 4] assoc :person/age 33)
(get-in state-db [:person/id 4])
{:person/id
{1 {:person/id 1 :person/name "Joe"
:person/spouse [:person/id 2] ; to-one
:person/children [[:person/id 3]
[:person/id 4]]} ; to-many
2 {:person/id 2 :person/name "Julie"
:person/spouse [:person/id 1]}}}
:ui/name
(ignored by server queries):entity-type/index-indicator
(e.g., :person/id
):root/prop-name
:entity-type/property-name
[:component/id ::Component]
The graph database is central to Fulcro operation:
;; Example manipulation
(swap! state (fn [s]
(-> s
(assoc :root/people [[:person/id 1] [:person/id 2]])
(assoc-in [:person/id 2 :person/name] "George")
(assoc-in [:person/id 2 :person/age] 33))))
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
Ctrl+k | Jump to recent docs |
← | Move to previous article |
→ | Move to next article |
Ctrl+/ | Jump to the search field |