This document describes how to migrate Reagent components to UIx, including syntactical differences and how various patterns in Reagent translate to UIx. UIx doesn't provide any abstractions on top of React, thus it is recommended to make yourself familiar with React in general. Also make sure to check out this slide deck.
$
macro instead of vector-based Hiccup
;; Reagent
[:div#id.class {:on-click f}
[:div]]
;; UIx
($ :div#id.class {:on-click f}
($ :div))
uix.core/defui
macro instead of defn
;; Reagent
(defn avatar [{:keys [src]}]
[:img {:src src}])
;; UIx
(defui avatar [{:keys [src]}]
($ :img {:src src}))
uix.core/use-state
hook instead of r/with-let
or a closure + r/atom
;; Reagent
(defn counter [props]
(let [state (r/atom 0)]
(fn [props]
[:button {:on-click #(swap! state inc)} @state])))
(defn counter [props]
(r/with-let [state (r/atom 0)]
[:button {:on-click #(swap! state inc)} @state]))
;; UIx
(defui counter [props]
(let [[value set-value!] (uix/use-state 0)]
($ :button {:on-click #(set-value! inc)} value)))
A single map of props instead of arbitrary positional arguments
;; Reagent, positional arguments
(defn button [{:keys [on-click]} text]
…)
[button {:on-click f} "press"]
;; UIx, a single argument of props
(defui button [{:keys [on-click text]}]
…)
($ button {:on-click f :text "press"})
Child elements are always put under :children
key in props map, instead of being positional arguments
;; Reagent, positional arguments
(defn button [{:keys [on-click]} text]
…)
[button {:on-click f} "press"]
;; UIx, :children key in props map
(defui button [{:keys [on-click children]}]
…)
($ button {:on-click f} "press")
While arguably in Reagent a one-to-one mapping between arguments and parameters is more straightforward than having implicit :children
key in React/Ux, the ergonomics of this approach becomes more apparent when one needs to "insert" children
into UI tree.
;; Reagent
(defn button [{:keys [on-click]} & children] ;; rest args
;; splicing into Hiccup form
(into [:button {:on-click on-click}]
children))
[button {:on-click f} "press" "me"]
;; UIx
(defui button [{:keys [on-click children]}] ;; :children key
;; passing `children` as is
($ :button {:on-click on-click} children))
($ button {:on-click f} "press")
key
attribute in child elements;; Reagent
(defn ui-list [{:keys [items]}]
[:ul
(for [item items]
^{:key (:id item)} ;; or as an attribute
[:li (:name item)])])
;; UIx
(defui ui-list [{:keys [items]}]
($ :ul
(for [item items]
($ :li {:key (:id item)} ;; only as attribute
(:name item)))))
In Reagent it's common to have shared state in the form of a global var that holds an r/atom
. In UIx and React shared state is not global at the namespace level, instead it's a local state that lives in UI tree and is being shared down the tree via React Context.
;; Reagent
(def state (r/atom 0)) ;; declare shared state
(defn child-component []
[:button
{:on-click #(swap! state inc)}]) ;; update the shared state
(defn parent-component []
(let [value @state] ;; consume the shared state
[child-component]))
;; UIx
;; declare means of sharing value in UI tree
(def state-context (uix.core/create-context []))
(defui child-component []
;; consume state from the context
(let [[n set-n!] (uix/use-context state-context)]
($ :button {:on-click #(set-n! inc)} n)))
(defui parent-component []
;; declare local state to be shared in UI subtree
(let [[n set-n!] (uix/use-state 0)]
;; share the state with the subtree via context
($ (.-Provider state-context) {:value [n set-n!]}
($ child-component))))
If you need to render a reagent component inside a UIX component:
[reagent.core :as r]
($ :div
(r/as-element [:div "hello"]))
Can you improve this documentation? These fine people already did:
roman01la, Roman Liutikov, Emil Lewandowski & Shaun MahoodEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close