Experimental ClojureScript wrapper for modern React.js
Bug reports, feature requests and PRs are welcome 👌
There are no versioned releases yet, use deps.edn
to depend on the code via git deps.
(require '[uix.core.alpha :as uix])
(defn button [{:keys [on-click]} text]
[:button.btn {:on-click on-click}
text])
(defn app []
(let [state (uix/state 0)]
[:<>
[button {:on-click #(swap! state dec)} "-"]
[:span @state]
[button {:on-click #(swap! state inc)} "+"]]))
(uix/render [button {:on-click js/console.log} "button"])
- State hook
- Global state and effects
- Dynamic styles
- Lazy loading
- Server-side rendering
- Interop between UIx and JS components
- Popups
[:div#id.class]
or[:#id.class]
[:> js/Component attrs & children]
- interop with JS components[:<> attrs & children]
-React.Fragment
[:-> element :#selector]
or[:-> element dom-node]
-React.createPortal
[:# {:fallback element} & children]
-React.Suspense
React Hooks in idiomatic Clojure style
;; state hook
;; (mutable ref type, re-renders component when mutated)
(let [state (uix/state 0)]
(swap! state inc)
@state) ; 1
;; ref hook
;; (mutable ref type, doesn't cause re-renders)
(let [ref (uix/ref 0)]
(swap! ref inc)
@ref) ; 1
;; effect hook
(uix/effect!
(fn []
(prn "after update")
#(prn "before unmount"))
[deps])
;; convenience macro for uix.core/effect!
(uix/with-effect [deps]
(prn "after update")
#(prn "before unmount"))
;; more in uix.core.alpha ns
Injects provided function into attributes transformation stage. Could be used for various side effects, such as processing styles with CSS-in-JS libraries (see uix.recipes.dynamic-styles
).
(uix.core.alpha/add-transform-fn
(fn [attrs]
(my-transform-attrs attrs)))
NOTE: UIx interpreter is already super fast (2x faster than Reagent and only 1.5x slower than vanilla React). Use pre-compilation ONLY if you are hitting performance problems.
Optionally compiles Hiccup into inlined React elements at compile-time
(uix/html
[:h1 "Title"])
;; emits this
{
$$typeof: Symbol.for("react.element"),
key: null,
ref: null,
props: { children: "Title" },
_owner: null
}
Compiler will try to inline as much as possible based on type information provided by ClojureScript's compiler (inspired by “On fast ClojureScript React templates”). When it is unable to determine type of the value it will emit interpretation call for the value and print a warning asking to annotate a value with either ^:inline
or ^:interpret
.
uix.core.alpha/defui
does the same as html
macro and additionally skips type checking arguments if a spec is provided.
(s/fdef button
:args (s/cat :attrs map? :child string?)
(uix/defui button [{:keys [on-click]} child]
[:button {:on-click on-click} child])
Loading React components on-demand as Closure modules. See code splitting guide and how lazy loading is used in React with Suspense: guide.
(uix/require-lazy '[uix.components :refer [ui-list]])
[:# {:fallback "Loading..."}
(when show?
[ui-list])]
See an example in uix.recipes.server-rendering
(uix/render-to-string element) ;; see https://reactjs.org/docs/react-dom-server.html#rendertostring
(uix/render-to-static-markup element) ;; see https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup
;; Streaming HTML
(uix/render-to-stream element {:on-chunk f}) ;; see https://reactjs.org/docs/react-dom-server.html#rendertonodestream
(uix/render-to-static-stream element {:on-chunk f}) ;; see https://reactjs.org/docs/react-dom-server.html#rendertostaticnodestream
react x 23202 ops/s, elapsed 431ms
uix-compile x 21834 ops/s, elapsed 458ms
uix-interpret x 14368 ops/s, elapsed 696ms
reagent-interpret x 7174 ops/s, elapsed 1394ms
lib | test 1 | test 2 | test 3 |
---|---|---|---|
rum | 107.8 µs | 3.6 ms | 7.7 ms |
uix | 120.8 µs | 3.8 ms | 8.1 ms |
uix streaming | 115.7 µs | 3.4 ms | 7.6 ms |
hiccup | 205.7 µs | 6.5 ms | 16.6 ms |
lib | size | gzip |
---|---|---|
rum | 254KB | 70KB |
reagent | 269KB | 74KB |
uix | 234KB | 65KB |
- Recipes
clojure -A:dev -m figwheel.main -O advanced -bo dev:prod
- Benchmark
clojure -A:dev:benchmark -m figwheel.main -O advanced -bo benchmark
- SSR Benchmark
clojure -A:dev:benchmark -m uix.benchmark
- Tests
clojure -A:dev:test -m cljs.main -re node -m uix.compiler-test