### Defining a Rum Component for Rendering Example (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Defines a Rum component `repeat-label` that takes a number `n` and text, and replicates a label element `n` times using `replicate`. ```Clojure (require [rum.core :as rum]) (rum/defc repeat-label [n text] [:div (replicate n [:.label text])]) ``` -------------------------------- ### Start, Stop, and Print React Performance Metrics (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Demonstrates how to use the React performance profiling tools from ClojureScript. It shows calling `js/React.addons.Perf.start`, `js/React.addons.Perf.stop`, and `js/React.addons.Perf.printWasted` to measure and report component rendering performance. ```ClojureScript (js/React.addons.Perf.start) ;;run your app (js/React.addons.Perf.stop) (js/React.addons.Perf.printWasted) ``` -------------------------------- ### Installing a Google Closure Keyboard Shortcut in Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/doc/useful-mixins.md Provides a utility function to install a keyboard shortcut handler using Google Closure Library. It registers a shortcut on a target element (defaulting to window) and returns a function to unregister the listener. It supports triggering the handler once. ```clojure (ns you-tools.keyboard (:require [goog.events :as events] [goog.ui.KeyboardShortcutHandler.EventType :as EventType] [goog.events.KeyCodes :as KeyCodes]) (:import [goog.ui KeyboardShortcutHandler])) (defn install-shortcut! "Installs a Keyboard Shortcut handler. The key is a string the trigger is a function that will receive the keyboard event as the first argument. If once? is true the keyboard shortcut is only fired once. The unregister handler is returned and can be called to unregister the listener. If target is not given it's attached to window." ([key trigger] (install-shortcut! key trigger false js/window)) ([key trigger once?] (install-shortcut! key trigger once? js/window)) ([key trigger once? target] (let [handler (new KeyboardShortcutHandler target)] (.registerShortcut handler (str key once?) key) (events/listen handler EventType/SHORTCUT_TRIGGERED (fn [e] (trigger e) (when once? (.unregisterShortcut handler keys)))) (fn [] (.unregisterShortcut handler key))))) ``` -------------------------------- ### Example Internal Rum Component State Structure - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Illustrates the structure of the internal state map maintained by a Rum component, showing how arguments (`:rum/args`) and the corresponding React component instance (`:rum/react-component`) are stored. ```Clojure { :rum/args ["Your name" ""] :rum/react-component } ``` -------------------------------- ### Implementing Server-Side Rendering and Hydration with Rum - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Shows the basic setup for server-side rendering (SSR) and client-side hydration using Rum. `rum/render-html` is used on the server (JVM) to generate an HTML string, and `rum/hydrate` is used on the client (ClojureScript) to attach component logic to the server-rendered markup. Requires specific dependency configuration excluding React/ReactDOM from the Rum dependency. ```Clojure (require '[rum.core :as rum]) (rum/defc my-comp [s] [:div s]) ;; on a server (rum/render-html (my-comp "hello")) ;; => "
hello
" ;; on a client (rum/hydrate (my-comp "hello") js/document.body) ``` -------------------------------- ### Create React Element for react-component/slider (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Shows another example of using `js/React.createElement` to create an instance of a 3rd-party React component (`js/Slider`). It demonstrates passing configuration options like `min`, `max`, `range`, and `defaultValue` as a JavaScript object. ```ClojureScript (defn range-slider [min max] (js/React.createElement js/Slider #js { :min min :max max :range true :defaultValue #js [40 60] })) ``` -------------------------------- ### Creating a Component-Specific Keyboard Shortcut Mixin in Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/doc/useful-mixins.md Defines a Rum mixin that installs a keyboard shortcut listener when the component mounts and removes it when it unmounts. The shortcut can be attached to a specific DOM target element or defaults to the window. It uses the `install-shortcut!` function internally. ```clojure (defn keyboard-mixin "Triggers f when key is pressed while the component is mounted. if target is a function it will be called AFTER the component mounted with state and should return a dom node that is the target of the listener. If no target is given it is defaulted to js/window (global handler) Ex: (keyboard-mixin \"esc\" #(browse-to :home/home))" ([key f] (keyboard-mixin key f js/window)) ([key f target] (let [target-fn (if (fn? target) target (fn [_] target))] {:did-mount (fn [state] (assoc state ::keyboard-listener (keyboard/install-shortcut! key f false (target-fn state)))) :will-unmount (fn [state] ((::keyboard-listener state)) state)}))) ``` -------------------------------- ### Using React Hooks with Rum Components - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Demonstrates the usage of various React hooks within Rum `defc` components. Includes examples for state management (`use-state`, `use-reducer`), side effects (`use-effect!`), memoization (`use-callback`, `use-memo`), and mutable references (`use-ref`). Note that hooks are only compatible with `defc` components and cannot be used with traditional mixins. ```Clojure ;; Takes initial value or value returning fn and returns a tuple of [value set-value!], ;; where `value` is current state value and `set-value!` is a function that schedules re-render. (let [[x set-x!] (rum/use-state 0)] (set-x! (inc x))) ;; Takes reducing function and initial state value. ;; Returns a tuple of [value dispatch!], where `value` is current state value and `dispatch` is a function that schedules re-render. (rum/use-reducer reducer-fn initial-value) ;; Takes setup-fn that executes either on the first render or after every update. ;; The function may return cleanup-fn to cleanup the effect, either before unmount or before every next update. ;; Calling behavior is controlled by deps argument. (rum/use-effect! (fn [] (.addEventListener js/document "keydown" js/console.log) #(.removeEventListener js/document "keydown" js/console.log)) []) ;; Takes callback function and returns memoized variant, memoization is done based on provided deps collection. (rum/defc component [x] (let [on-change (rum/use-callback #(js/console.log % x) [x])] [input-field {:on-change on-change}])) ;; Takes a function, memoizes it based on provided deps collection and executes immediately returning a result. (let [x (rum/use-memo #(expensive-computation v) [v])]) ;; Takes a value and puts it into a mutable container which is persisted for the full lifetime of the component. (rum/defc component [] (let [ref (rum/use-ref nil)] (rum/use-effect! #(.log js/console (rum/deref ref))) [:input {:ref ref}])) ``` -------------------------------- ### Configure Leiningen Dependencies for React with Addons (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Configures project dependencies in `project.clj` to include `cljsjs/react-with-addons` and related React DOM libraries, excluding standard React dependencies. This setup is necessary for using React features like the performance profiling tools. ```Clojure [rum "0.11.3" :exclusions [cljsjs/react cljsjs/react-dom]] [cljsjs/react-dom "16.2.0-3" :exclusions [cljsjs/react]] [cljsjs/react-dom-server "16.2.0-3" :exclusions [cljsjs/react]] [cljsjs/react-with-addons "16.2.0-3"] ``` -------------------------------- ### Deprecated Ref/DOM Node Helpers in ClojureScript Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Provides examples of deprecated helper functions (`rum/dom-node`, `rum/ref`, `rum/ref-node`) that were previously used to access the top-level DOM node or ref-ed components/nodes from the component state. ```ClojureScript (rum/dom-node state) ;; => top-level DOM node (rum/ref state "x") ;; => ref-ed React component (rum/ref-node state "x") ;; => top-level DOM node of ref-ed React component ``` -------------------------------- ### Install/Uninstall CSS Styles Mixin (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/useful-mixins.md This mixin installs CSS styles when a component mounts and uninstalls them when it unmounts, using `goog.style`. It's particularly useful in development for applying styles defined in `.cljc` files, allowing live updates without a full page reload. ```Clojure (ns ... (:require [goog.style :as gstyle])) (defn install-styles-mixin "Installes the stylesheet when mounting. Uninstall when unmount. Useful for use at the very root render and use with garden in a cljc environment. Live update of CSS without needing to go trough figwheel :)" [css-str] {:will-mount (fn [st] (assoc st ::stylesheet (gstyle/installStyles css-str))) :will-unmount (fn [st] (gstyle/uninstallStyles (::stylesheet st)) st)}) ;; Then use them like so: app < (install-styles-mixin (your-cljc/gen-css)) ``` -------------------------------- ### Using Function Ref for DOM Node in ClojureScript Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Demonstrates how to use a function as the value for the `:ref` attribute on a DOM element tag to get direct access to the DOM node when it is mounted. ```ClojureScript [:div {:ref (fn [node] ...)}] ``` -------------------------------- ### Get Component Display Name from Rum State (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Shows how to retrieve the `displayName` property of the underlying React component from the Rum component's state map. This is useful for debugging and development purposes, often used within mixins. ```ClojureScript (ns ... (:require [goog.object :as gobj])) (defn display-name "Returns the displayname of the component" [state] (gobj/getValueByKeys (:rum/react-component state) "constructor" "displayName")) ``` -------------------------------- ### Performing Side Effects with rum/use-effect! in ClojureScript Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-hooks.md This example illustrates the use of the `rum/use-effect!` hook to manage side effects in a Rum component. It adds a global `keydown` event listener when the component updates and removes it via the returned cleanup function before the next update or unmount. This pattern is useful for effects that need to synchronize with component updates. ```ClojureScript (rum/defc input-field [] (rum/use-effect! (fn [] (let [handler #(println :key (.-key %))] (.addEventListener js/document "keydown" handler) #(.removeEventListener js/document "keydown" handler)))) ...) ``` -------------------------------- ### Creating a Reactive Rum Component with `rum.core/reactive` (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Illustrates how to make a component automatically re-render when a watched atom changes by including the `rum.core/reactive` mixin and using `rum.core/react`. ```Clojure (def count (atom 0)) (rum/defc counter < rum/reactive [] [:div { :on-click (fn [_] (swap! count inc)) } "Clicks: " (rum/react count)]) (rum/mount (counter) js/document.body) ``` -------------------------------- ### Mounting a Rum Component to the DOM (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Illustrates how to render a Rum component instance onto a specific DOM node using `rum.core/mount`. This is typically used once for the root component. ```Clojure (rum/mount (repeat-label 5 "abc") js/document.body) ``` -------------------------------- ### Basic HTML Structure for ClojureScript Code-Splitting Output Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-suspense-and-code-splitting.md Provides the minimal HTML structure required to load the generated ClojureScript code-splitting chunks. It includes a `div` element with the ID "root" where the Rum application will be mounted and script tags to load the base and core JavaScript files generated by the build process. ```HTML
``` -------------------------------- ### Configuring ClojureScript Code-Splitting Modules in build.edn Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-suspense-and-code-splitting.md Defines the build configuration for ClojureScript using `build.edn`, specifying output directory, asset path, optimizations, and multiple code modules (`:core` and `:components`) with their entry points and output files for code-splitting. ```Clojure {:output-dir "resources/public/out" :asset-path "out" :optimizations :advanced :modules {:core {:entries #{example.core} :output-to "resources/public/out/core.js"} :components {:entries #{example.components} :output-to "resources/public/out/components.js"}}} ``` -------------------------------- ### Defining a Basic Rum Component (defc) - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Shows how to define a simple Rum component using `rum/defc` with arguments and basic Hiccup syntax. This macro handles internal state management automatically. ```Clojure (rum/defc input [label value] [:label label ": " [:input { :value value }]]) (input "Your name" "") ``` -------------------------------- ### Defining a Basic Rum Component in Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Demonstrates how to define a simple functional component using `rum.core/defc` that accepts arguments and returns Hiccup markup. ```Clojure (require [rum.core :as rum]) (rum/defc label [text] [:div {:class "label"} text]) ``` -------------------------------- ### Using New React Context API in ClojureScript Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Demonstrates the new React Context API in Rum using `rum/defcontext` to define a context, `rum/with-context` to consume it, and `rum/bind-context` to provide a value. ```ClojureScript (rum/defcontext *context*) (rum/defc context-consumer [] (rum/with-context [value *context*] value)) ;; "hello" (rum/defc context-provider [] (rum/bind-context [*context* "hello"] (context-consumer)) ``` -------------------------------- ### Implementing a Rum Mixin with will-mount - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Shows how to define a mixin that includes a `:will-mount` callback function. This function receives the component's state and can modify it (e.g., add data) just before the component is mounted to the DOM. ```Clojure (rum/defcs time-label < { :will-mount (fn [state] (assoc state ::time (js/Date.))) } [state label] [:div label ": " (str (::time state))]) ``` -------------------------------- ### Manually Updating a Rum Component by Remounting (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Demonstrates a simple, though often inefficient, method of updating a component by repeatedly remounting it to the DOM using `js/setInterval`. ```Clojure (rum/defc timer [] [:div (.toISOString (js/Date.))]) (rum/mount (timer) js/document.body) (js/setInterval #(rum/mount (timer) js/document.body) 1000) ``` -------------------------------- ### Lazy Loading and Suspending a Rum Component in ClojureScript Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-suspense-and-code-splitting.md Defines the main `example.core` namespace. It uses `rum.lazy-loader/require-lazy` to lazily load the `alert` component from the `example.components` namespace (which is in a different chunk). The `alert` component is then wrapped in `rum/suspense` to display a fallback ("Hello!") while the component's chunk is loading. Finally, it mounts the root component and signals the chunk is loaded. ```ClojureScript (ns example.core (:require [cljs.loader :as loader] [rum.core :as rum] [rum.lazy-loader :refer [require-lazy]])) (require-lazy '[example.components :refer [alert]]) (rum/defc root [] (rum/suspense {:fallback "Hello!"} (alert "ARGUMENT"))) (loader/set-loaded! :core) (rum/mount (root) (.getElementById js/document "root")) ``` -------------------------------- ### Adding Rum Dependency to project.clj Source: https://github.com/tonsky/rum/blob/gh-pages/README.md This snippet shows how to add the Rum library as a dependency to your Clojure/ClojureScript project using Leiningen or Boot by including the library coordinates in the `project.clj` file. ```Clojure [rum \"0.12.11\"] ``` -------------------------------- ### Create Placeholder Namespace for Manual React Inclusion (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Creates a placeholder ClojureScript file for the `cljsjs.react` namespace. This is necessary when including React manually via script tags to satisfy ClojureScript compiler requirements without bundling the library. ```ClojureScript (ns cljsjs.react) ``` -------------------------------- ### List of Available Rum Mixin Lifecycle Callbacks - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Provides a comprehensive list of the lifecycle callback functions that can be defined within a Rum mixin, detailing their names and the arguments they receive (typically the component state). ```Clojure { :init ;; state, props ⇒ state :will-mount ;; state ⇒ state :before-render ;; state ⇒ state :wrap-render ;; render-fn ⇒ render-fn :render ;; state ⇒ [pseudo-dom state] :did-catch ;; state, err, info ⇒ state :did-mount ;; state ⇒ state :after-render ;; state ⇒ state :will-remount ;; old-state, state ⇒ state :should-update ;; old-state, state ⇒ boolean :will-update ;; state ⇒ state :did-update ;; state ⇒ state :will-unmount } ;; state ⇒ state ``` -------------------------------- ### Combining Multiple Rum Mixins - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Illustrates how a single Rum component can incorporate multiple mixins using the `<` syntax, allowing the composition of different behaviors and state management features. ```Clojure (rum/defcs component < rum/static rum/reactive (rum/local 0 ::count) (rum/local "" ::text) [state label] (let [count-atom (::count state) text-atom (::text state)] [:div])) ``` -------------------------------- ### Optimizing Rum Component Rendering with rum.core/static (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/README.md This code illustrates how to use the `rum.core/static` mixin to optimize Rum components that receive only immutable data as arguments. By adding `< rum/static` to the component definition, Rum will check if the component's arguments have changed using Clojure's `-equiv` semantic and skip re-rendering if they are the same, improving performance. ```Clojure (rum/defc label < rum/static [n text] [:.label (replicate n text)]) ``` -------------------------------- ### Creating React Fragments with Rum - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Illustrates how to use the `:<>` tag within a Rum markup vector to create a React Fragment. This allows rendering multiple child elements without the need for a single wrapping DOM element. ```Clojure [:<> [:span] [:div] [:span]] ;;
``` -------------------------------- ### Performing Static Server-Side Rendering with Rum - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Demonstrates the use of `rum/render-static-markup` for server-side rendering when client-side hydration is not intended. This function renders the component to a plain HTML string without adding React-specific attributes. ```Clojure (rum/render-static-markup (my-comp "hello")) ;; =>
hello
``` -------------------------------- ### Defining a Rum Component in a Separate ClojureScript Code Chunk Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-suspense-and-code-splitting.md Defines a simple Rum component `alert` within the `example.components` namespace. It explicitly calls `cljs.loader/set-loaded!` to signal that this code chunk (`:components`) has finished loading, which is necessary for the code-splitting runtime. ```ClojureScript (ns example.components (:require [rum.core :as rum] [cljs.loader :as loader])) (rum/defc alert [arg] [:h1 arg]) (loader/set-loaded! :components) ``` -------------------------------- ### Define Component with Mixins (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/CHANGELOG.md This snippet shows the new syntax introduced in version 0.2.0 for defining a Rum component using the `defc` macro. It demonstrates how to include mixins, define arguments, and provide the component's body. ```ClojureScript (defc name < mixin1 mixin2 [args] body...) ``` -------------------------------- ### Create Placeholder Namespace for Manual React DOM Inclusion (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Creates a placeholder ClojureScript file for the `cljsjs.react.dom` namespace. This is required when including React DOM manually via script tags to satisfy ClojureScript compiler requirements without bundling the library. ```ClojureScript (ns cljsjs.react.dom) ``` -------------------------------- ### Defining a Stateful Rum Component with Local Atom (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/README.md This snippet demonstrates how to create a Rum component (`stateful`) that manages its own local state using `rum.core/local`. It shows how to use `rum.core/defcs` to access the component's internal state, extract the local atom, and update it using `swap!`. Changes to the local atom automatically trigger a component re-render. ```Clojure (rum/defcs stateful < (rum/local 0 ::key) [state label] (let [local-atom (::key state)] [:div { :on-click (fn [_] (swap! local-atom inc)) } label ": " @local-atom])) (rum/mount (stateful "Click count") js/document.body) ``` -------------------------------- ### Performance Considerations for Hiccup Compilation in Rum (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Compares using `for` (pre-compiled) versus `map` (interpreted) within a Rum component's Hiccup structure, highlighting performance implications. ```Clojure (rum/defc component [] [:ul (for [n (range 10)] [:li n]) ;;`for` is a known form with a well defined syntax, thus Hiccup is pre-compiled (map (fn [n] [:li n]) ;;`map` is a generic higher-order function, can't reliably pre-compile, falling back to interpretation (range 10))]) ``` -------------------------------- ### Mix React.createElement with Daiquiri HTML Syntax (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Demonstrates how to combine direct `js/React.createElement` calls with the Hiccup-like syntax provided by the Daiquiri library. This is useful for passing children defined using Hiccup syntax to a 3rd-party React component. ```ClojureScript (js/React.createElement js/MyComponent #js { } (daiquiri.core/html [:div [:p "Hello, world"]])) ``` -------------------------------- ### Specifying React Key with rum/with-key in Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Illustrates how to explicitly set a React `key` for a Rum component instance using the `rum/with-key` helper function, useful when rendering lists of components. ```Clojure (rum/defc my-component [str] ...) (rum/with-key (my-component "args") "x") ``` -------------------------------- ### Creating a Periodic Update Rum Mixin - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Defines a mixin that uses `:did-mount` to set up a JavaScript interval timer to request component re-renders and `:will-unmount` to clear the timer, demonstrating how mixins can manage side effects and schedule updates. ```Clojure (def periodic-update-mixin { :did-mount (fn [state] (let [comp (:rum/react-component state) callback #(rum/request-render comp) interval (js/setInterval callback 1000)] (assoc state ::interval interval))) :will-unmount (fn [state] (js/clearInterval (::interval state)) (dissoc state ::interval)) }) (rum/defc timer < periodic-update-mixin [] [:div (.toISOString (js/Date.))]) (rum/mount (timer) js/document.body) ``` -------------------------------- ### Enabling Rum Hiccup Interpretation Warnings (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Shows how to enable a compiler flag using `rum.core/set-warn-on-interpretation!` to receive warnings about Hiccup forms that are interpreted at runtime rather than pre-compiled. ```Clojure (rum.core/set-warn-on-interpretation! true) ``` -------------------------------- ### Create React Element for react-router-transition (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Illustrates how to directly use `js/React.createElement` from ClojureScript to instantiate a 3rd-party React component (`js/RouteTransition`). It shows passing props as a JavaScript object (`#js {}`) and converting Clojure children to JavaScript using `clj->js`. ```ClojureScript (defn route-transition [pathname children] (js/React.createElement js/RouteTransition #js { :pathname pathname :atEnter #js { :opacity 0 } :atLeave #js { :opacity 0 } :atActive #js { :opacity 1 } } (clj->js children))) ``` -------------------------------- ### Calculating React Key with :key-fn Mixin in Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Explains how to define a `:key-fn` within a component's mixin to dynamically calculate the React `key` based on the component's arguments when it is created. ```Clojure (rum/defc my-component < { :key-fn (fn [x y z] (str x "-" y "-" z)) } [x y z] ...) (my-component 1 2 3) ;; => key == "1-2-3" ``` -------------------------------- ### Fast Equality Check with Identity Source: https://github.com/tonsky/rum/blob/gh-pages/doc/optimizations.md Demonstrates a fast equality check using `=` when comparing a value to itself. Clojure's `=` leverages `identical?` for identity checks, which is very quick when structural sharing (or identity) exists. ```Clojure (def x {:key :value}) (= x x) ``` -------------------------------- ### Using Legacy React Child Context API in ClojureScript Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Illustrates the deprecated legacy React child context API in Rum, requiring `cljsjs/prop-types` and using the `:child-context` function and `:static-properties` with `childContextTypes` mixins. ```ClojureScript (rum/defc theme < { :child-context (fn [state] (let [[color] (:rum/args state)] { :color color })) :static-properties { :childContextTypes {:color js/PropTypes.string} } } [color child] child) ``` -------------------------------- ### Define JVM Fallback Renderer for JS Components (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Provides a function `render-js-component` to handle rendering of JavaScript components when running on the JVM (e.g., for server-side rendering). It demonstrates how to use `binding` with `rum/*render-js-component*` to provide a custom rendering strategy, such as rendering a placeholder. ```ClojureScript (defn render-js-component [type-sym attrs children] (case type-sym 'js/Slider (rum/render-static-markup (slider-placeholder)) nil)) (binding [rum/*render-js-component* render-js-component] (component)) ``` -------------------------------- ### Using Rum Cursors with Atoms - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Explains and demonstrates `rum/cursor-in`, a function that creates an atom-like interface to a nested value within a larger atom, enabling localized reads and writes that synchronize with the parent atom. ```Clojure (def state (atom { :color "#cc3333" :user { :name "Ivan" } })) (def user-name (rum/cursor-in state [:user :name])) @user-name ;; => "Ivan" (reset! user-name "Oleg") ;; => "Oleg" @state ;; => { :color "#cc3333" ;; :user { :name "Oleg" } } ``` -------------------------------- ### Using rum/create-ref for Component/DOM Node in ClojureScript Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Shows how to use `rum/create-ref` to create a mutable ref object and assign it to the `:ref` attribute, allowing access to the component instance or DOM node via `rum/deref`. ```ClojureScript (let [ref (rum/create-ref)] [:input {:ref ref :on-change #(.log js/console (rum/deref ref))}]) ``` -------------------------------- ### Accessing Rum Component State (defcs) - Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Demonstrates using the `rum/defcs` macro, which is similar to `defc` but explicitly passes the internal `state` map as the first argument to the render function, allowing direct access to state data. ```Clojure (rum/defcs label [state label value] [:div "My args:" (pr-str (:rum/args state))]) (label "A" 3) ;; =>
My args: ["A" 3]
``` -------------------------------- ### Configure Leiningen Dependencies for Manual React Inclusion (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Sets up project dependencies in `project.clj` to exclude `cljsjs/react` and `cljsjs/react-dom` from the Rum dependency, allowing React and React DOM to be included manually via script tags in the HTML. ```Clojure :dependencies { [rum "0.11.3" :exclusions [[cljsjs/react] [cljsjs/react-dom]]] } ``` -------------------------------- ### Adapt 3rd-Party React Component with rum/adapt-class (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Shows how to use Rum's `adapt-class` function to wrap a 3rd-party React component (`js/Slider`) within a Rum component. This allows using standard React components with Rum's Hiccup-like syntax, passing props as a Clojure map. ```ClojureScript (rum/defc component [] [:div (rum/adapt-class js/Slider {:min min :max max :range true :defaultValue [40 60]})]) ``` -------------------------------- ### Include React and React DOM via Script Tags (HTML) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Adds script tags to the HTML file to load React and React DOM from a CDN. This is used when the dependencies are excluded from the ClojureScript build and included manually. ```HTML ``` -------------------------------- ### Accessing Native React Component/DOM in ClojureScript Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Shows how to access the underlying React component instance and its corresponding DOM node within a Rum component's `:did-mount` lifecycle method using the `:rum/react-component` state attribute and `js/ReactDOM.findDOMNode`. ```ClojureScript { :did-mount (fn [state] (let [comp (:rum/react-component state) dom-node (js/ReactDOM.findDOMNode comp)] (set! (.-width (.-style dom-node)) "100px")) state) } ``` -------------------------------- ### Using derived-atom in Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Demonstrates how to create a derived atom that depends on multiple source atoms. It shows how changes in source atoms trigger recalculation and update the derived atom's value. ```Clojure (def *a (atom 0)) (def *b (atom 1)) (def *x (derived-atom [*a *b] ::key (fn [a b] (str a ":" b)))) (type *x) ;; => clojure.lang.Atom @*x ;; => 0:1 (swap! *a inc) @*x ;; => 1:1 (reset! *b 7) @*x ;; => 1:7 ``` -------------------------------- ### Configure Leiningen Dependencies for Specific React Version (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Configures the project dependencies in `project.clj` to exclude the default `cljsjs/react` and `cljsjs/react-dom` provided by Rum and include specific versions instead. This allows using a different React version than the one bundled with Rum. ```Clojure :dependencies { [rum "0.11.3" :exclusions [[cljsjs/react] [cljsjs/react-dom]]] [cljsjs/react "16.6.0-0"] [cljsjs/react-dom "16.6.0-0"] } ``` -------------------------------- ### Defining Static Class Properties with Mixin in Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Shows how to use the `:static-properties` mixin map to define static properties directly on the generated React component class. ```Clojure (rum/defc comp < { :static-properties { ... } } [:div])) ``` -------------------------------- ### Wrap Rum Component for Use in React (ClojureScript) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-interop.md Provides a pattern for using a Rum component (`button`) from standard React JavaScript code. It defines a wrapper function (`Button`) that takes React's JavaScript props object, extracts values, and passes them as arguments to the Rum component. ```ClojureScript (rum/defc button [{:keys [on-click]} text] [:button {:on-click on-click} text]) (defn Button [^js props] (button {:on-click (.-onClick props)} (.-children props))) ``` -------------------------------- ### Defining Custom Class Properties with Mixin in Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Shows how to use the `:class-properties` mixin map to define arbitrary properties and methods directly on the generated React component class. ```Clojure (rum/defc comp < { :class-properties { ... } } [:div])) ``` -------------------------------- ### Defining Component Attributes in Rum Hiccup (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/README.md Shows how to specify attributes for a Hiccup element in Rum, including standard attributes, class sequences, style maps, and event handlers. ```Clojure [:input { :type "text" :allow-full-screen true :id "comment" :class ["input_active" "input_error"] :style { :background-color "#EEE" :margin-left 42 } :on-change (fn [e] (js/alert (.. e -target -value))) }] ``` -------------------------------- ### Deep Equality Check on New Values Source: https://github.com/tonsky/rum/blob/gh-pages/doc/optimizations.md Illustrates a potentially slower equality check using `=` between two distinct, newly created values. Since there is no structural sharing, `=` performs a deep value comparison. ```Clojure (= {:key :value} {:key :value}) ``` -------------------------------- ### Performance Measurement Mixin (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/useful-mixins.md Provides a mixin and helper macro to measure the rendering time of a component in development environments. It uses `console.time` and `console.timeEnd` to log the duration of the render function execution. ```Clojure (defn perf-measure-mixin [desc] "Does performance measurements in development." {:wrap-render (fn wrap-render [render-fn] (fn [state] (profile (str "Render " desc) (render-fn state))))}) ;; where profile is a macro like this: (defmacro profile [k & body] (if macros/dev? `(let [k# ~k] (.time js/console k#) (let [res# (do ~@body)] (.timeEnd js/console k#) res#)) `(do ~@body))) ``` -------------------------------- ### Using rum/use-memo for Caching in Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-hooks.md This snippet demonstrates how to use the `rum/use-memo` hook within a `rum/defc` component to cache an instance of a JavaScript class. The instance is created only when the `config` dependency changes, preventing unnecessary re-instantiation on every render. ```clojure (rum/defc component [config] (let [js-lib (rum/use-memo #(js/LibClass. config) [config])] ...)) ``` -------------------------------- ### Managing Local State with rum/use-state in ClojureScript Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-hooks.md This snippet shows how to use the `rum/use-state` hook in a Rum `defc` component. It initializes a local state variable `value` with an empty string and provides a `set-value!` function to update it. The state and setter are then used to control an input field's value and handle its `on-change` event. ```ClojureScript (rum/defc input-field [] (let [[value set-value!] (rum/use-state "")] [:input {:value value :on-change #(set-value! (.. % -target -value))}])) ``` -------------------------------- ### Equality Check with Partial Structural Sharing Source: https://github.com/tonsky/rum/blob/gh-pages/doc/optimizations.md Shows an equality check using `=` between an original value and an updated version. The check is optimized because parts of the data structure are shared and checked quickly via `identical?`, while only the modified parts require a deeper comparison. ```Clojure (def x {:x {:a 1 :b 2} :y {:c 3 :d 4}}) (def y (update-in x [:x :a] inc)) (= x y) ``` -------------------------------- ### Debouncer Mixin for Rum Components (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/useful-mixins.md Provides a debouncing mechanism using Google Closure's `Debouncer`. The mixin creates a debouncer instance in the component state that can be triggered with `.fire`. It supports calling a predefined callback or a function passed directly to `.fire`. ```Clojure (ns ... (:import [goog.async Debouncer])) (defn debouncer-mixin "Creates a debouncer in (:debouncer state) which can be called with (.fire). Invokes the callback cb or invokes the first argument passed to fire. Usage: 1. (debouncer-mixin 200) (.fire (:debouncer state) #(do-actual-action ...)) 2. (debouncer-mixin 200 #(do-an-action ...)) (.fire (:debouncer state))" ([ms] (debouncer-mixin ms nil)) ([ms cb] {:will-mount (fn debouncer-mount [state] (assoc state :debouncer (Debouncer. (if (nil? cb) #(%1) cb) ms))) :will-unmount (fn debouncer-unmount [state] (.dispose (:debouncer state)) state)})) ``` -------------------------------- ### AJAX Request Mixin for Rum Components (Clojure) Source: https://github.com/tonsky/rum/blob/gh-pages/doc/useful-mixins.md This mixin performs an AJAX request when the component mounts. It stores the result in an atom within the component's state, updating the component when the data is received. It's designed to fetch data asynchronously and render the component based on the data's availability. ```Clojure (defn ajax-mixin [url key] { :will-mount (fn [state] (let [*data (atom nil) comp (:rum/react-component state)] (ajax url (fn [data] (reset! *data data) (rum/request-render comp))) (assoc state key *data))) }) (rum/defcs user-info < (ajax-mixin "/api/user/info" ::user) [state] (if-let [user @(::user state)] ... [:div "Loading..."])) ``` -------------------------------- ### Remembering Component Local State Across Mounts in Clojure Source: https://github.com/tonsky/rum/blob/gh-pages/doc/useful-mixins.md Defines a Rum mixin that persists the component's local state (`:rum/local`) in a global atom when the component unmounts and restores it when the component mounts again. It requires a function to generate a unique key for the component based on its arguments. ```clojure (defn remember-state-mixin "Remembers the state :rum/local for a given component and swaps it back on mount. The given function is passed the args of the component (with apply). And should return a map key that is used to uniquely identify the component. (remember-state-mixin (fn [arg1 arg2] (:db/id arg1)))" [f] (let [store (atom {}) key-fn (fn [state] (apply f (:rum/args state)))] {:will-unmount (fn remember-state-unmount [state] (swap! store assoc (key-fn state) @(:rum/local state)) state) :will-mount (fn remember-state-mount [state] (let [old-state @store key (key-fn state)] (swap! (:rum/local state) merge (get old-state key {})))) state)})) ``` -------------------------------- ### Caching Callbacks with rum/use-callback in ClojureScript Source: https://github.com/tonsky/rum/blob/gh-pages/doc/react-hooks.md This snippet shows how to use the `rum/use-callback` hook to cache a function reference. This is particularly useful when passing callbacks to memoized child components (`rum/static`) to prevent the child from re-rendering unnecessarily when the parent updates. The callback is only re-created if its dependencies (`[idx]` in this case) change. ```ClojureScript (rum/defc list-item* < rum/static [on-click] ...) (rum/defc list-item [idx on-click] (let [handle-click (rum/use-callback #(on-click idx %) [idx]) [list-item* handle-click]])) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.