re-frame.adapter.uix¶
The UIx adapter connects re-frame2's substrate-agnostic core to UIx, a hooks-first React substrate. It exposes:
- the hooks
use-subscribe,use-frame,use-resource-lease, anduse-current-frame; - the
frame-provider(SCOPE) +frame-root(ENSURE) components; - the
adapterspec map you pass toinit!; - adapter seams for tests, SSR, and code-gen.
It ships in the day8/re-frame2-uix artefact. The dependency direction is one-way: the adapter depends on re-frame.core, never the reverse. There is no auto-injection; UIx components read subscriptions with use-subscribe and take their frame ops (dispatch) off the use-frame hook directly.
Register views by Var (the React-component idiom) or with rf/reg-view* for registry-keyed view addressing. reg-view (the Reagent macro) does not cover UIx. A minimal app wires the adapter into init! and reads subscriptions through the hook:
(:require [re-frame.core :as rf]
[re-frame.adapter.uix :as uix-adapter]
[uix.core :refer [$ defui]])
(rf/init! uix-adapter/adapter)
(defui cart-row [{:keys [item]}]
(let [count (uix-adapter/use-subscribe [:cart/count])]
($ :tr
($ :td (:name item))
($ :td count))))
For narrative coverage and the substrate decision set, see Use UIx, Helix, or reagent-slim.
Adapter spec¶
adapter¶
- Kind: Var (map)
- Signature:
- Description: The adapter spec passed to
(rf/init! ...). Implements the same substrate adapter contract as the Reagent and Helix adapters.:kindis:rf.adapter/uix. - Example:
Hooks¶
use-subscribe¶
- Kind: UIx hook (function)
- Signature:
- Description: Subscribe inside a UIx component. This is the hook-shaped equivalent of
subscribe.
Returns the current sub value and re-renders the calling component when the value changes.
- The 1-arg form resolves the frame through the standard chain:
with-framedynamic scope first, then the surroundingframe-provider. It raises:rf.error/no-frame-contextwhen neither is in scope (there is no:rf/defaultfloor). - The 2-arg form pins to an explicit frame-id, bypassing the chain.
- Example:
use-frame¶
- Kind: UIx hook (function)
- Signature:
- Description: Returns the frame ops map for the ambient frame — exactly what
(rf/capture-frame)returns (the frame-locked ops map), captured in hook position. This is how a UIx component gets hold ofdispatch(and the other frame-locked ops) without auto-injection: destructuredispatchoff it and close over that.
capture-frame is the hold primitive; reg-view injection (Reagent) and use-frame (UIx / Helix) are its two ergonomic spellings — one primitive, three faces.
- Frame resolution matches
use-subscribe:with-framedynamic scope first, then the surroundingframe-provider/frame-rootvia React context. It raises:rf.error/no-frame-contextwhen neither is in scope. - The returned map is reference-stable across re-renders for the same resolved frame (safe in effect deps and child props); a provider swap re-renders the caller and yields a map locked to the new frame.
- No options map, no variants — for an explicit frame, call
(rf/capture-frame frame-id)directly. - Example:
use-resource-lease¶
- Kind: UIx hook (function)
- Signature:
- Description: Holds a resource liveness lease for the calling component's mounted lifetime. On mount, dispatches
:rf.resource/ensurewith an app-minted[:lease …]owner; on unmount, dispatches:rf.resource/release-ownerfor that same lease.
Returns nil: this is a lifecycle hook, not a read. Pair it with use-subscribe on a [:rf.resource/*] query to read the data.
descriptor— the resource-instance identity{:resource … :scope … :params …}.optskeys::cause(recorded on the ensure; defaults to[:lease :mount]) and:frame(pin to an explicit frame-id).- Without
:frame, frame resolution mirrorsuse-subscribe, raising:rf.error/no-frame-contextwhen no frame is in scope. - Changing the resolved frame, descriptor, or cause releases the old lease and takes a fresh one.
- The events are inert when the resources artefact is not loaded.
- Example:
use-current-frame¶
- Kind: UIx hook (function)
- Signature:
- Description: Returns the frame keyword supplied by the surrounding
frame-provider(SCOPE) orframe-root(ENSURE) — both install the one shared React context this read consults. It exists for components that thread the frame through hand-written child callbacks.
This hook reads the React-context tier only. When neither frame-provider nor frame-root sits above, it returns the no-provider sentinel :rf.frame/no-provider — never nil, and never a synthesised default. It does not consult the with-frame dynamic var; for the full resolution chain, use rf/current-frame-id.
NOT USED — no call sites found in
implementation/,examples/, ortools/.
Components¶
frame-provider¶
- Kind: UIx component (function — SCOPE-only)
- Signature:
- Description: The UIx-shaped SCOPE-only frame provider (rf2-nyea0r split — roots ensure; providers scope; for create-if-absent, use
frame-root). Scopes an already-created frame; creates nothing. Raises: :rf.error/frame-provider-frame-absentwhen the frame does not exist:rf.error/no-frame-contexton a nil:frame:rf.error/bad-frame-provider-argon a non-keyword:frame:rf.error/frame-provider-given-idwhen given an:id(the ENSURE key — useframe-root)
Children ride the idiomatic $ trailing-args channel. Pass them after the prop map, as for any other UIx component (there is no :children prop-map key).
- Example:
frame-root¶
- Kind: UIx component (function — ENSURE, a commit-owned two-pass boundary)
- Signature:
- Description: The UIx-shaped ENSURE component (rf2-nyea0r split). Creates the named frame if absent, or reuses it without re-seeding if present; never destroys the frame on unmount. Accepts
make-frameopts, including:images/:initial-events.:idmust be a keyword; a missing/nil/non-keyword:idraises:rf.error/frame-root-missing-id. - Commit-owned two-pass: the create/seed runs in a client
useLayoutEffect(at commit), not during render — the first render emits no descendant subtree, and children render only after the frame is live. A render React discards before commit creates + seeds nothing (no ghost frame). - Re-mounting under the same
:id(hot reload, React StrictMode dev double-invoke) neither destroys durable state nor re-runs:initial-events. A mounted:id/opts change raises:rf.error/frame-root-reconfigured; a stray:frameraises:rf.error/frame-root-given-frame.
Children ride the idiomatic $ trailing-args channel.
- Example:
;; create the frame on first mount, seed it once via :initial-events,
;; reuse (no re-seed) on hot-reload re-mount.
($ uix-adapter/frame-root {:id :app :initial-events [[:counter/initialise]]}
($ counter-app))
Adapter seams¶
wrap-view¶
- Kind: function
- Signature:
- Description: Adapter-side source-coord injection: wraps a component head so its rendered root DOM element carries
data-rf2-source-coordin debug builds (see the Notes below). Most users register throughreg-view*;wrap-viewis for code-gen and library scaffolding. - Example:
flush-views!¶
- Kind: function
- Signature:
- Description: Wraps React's
act()for tests. Flushes pending renders synchronously and returns nil. - Example:
set-hiccup-emitter!¶
- Kind: function
- Signature:
- Description: Install a render-tree → HTML fn. This is the UIx side of the SSR late-bind seam, at parity with the Reagent adapter. Normally you don't call this directly; requiring
re-frame.ssrwires the emitter for you. Passnilto reset. - Example:
Notes¶
- Shared React Context. The
frame-providerin all three adapters (Reagent, UIx, Helix) consumes the samecreateContextobject, factored intore-frame.adapter.context(a CLJS-only file in core). There is exactly one Context, not three. A mixed-substrate app therefore composes: a UIxframe-providercan wrap a Reagent or Helix subtree, and vice versa. - DOM source-coord annotations. Adapters inject
data-rf2-source-coordon every registered view's root element;wrap-viewis the explicit seam for that injection. The attribute is gated on debug builds and elided from production:advancedbuilds via dead-code elimination, so it costs no shipped bytes. It powers click-to-source in Xray and re-frame2-pair. The full contract is in the Observability concept guide.
See also¶
- re-frame.core — the substrate-agnostic ergonomic surface (
capture-frame,with-frame,with-new-frame,frame-provider) plus theinit!/install-adapter!/current-adapter/adapter-disposed?lifecycle. - re-frame.adapter.helix — the parallel hooks-first adapter; the UIx surface transfers to it one-for-one.
- re-frame.adapter.reagent — the default (inline) substrate.
- Use UIx, Helix, or reagent-slim — narrative coverage with worked examples and the full decision set.
- Adapter (glossary) — the substrate seam, defined.