How do you make hooks on the client side? Could you show me any example? Do you make the same components by invoking rum/hydrate? It’s interesting problem for me, because I don’t know how can I pass handlers (from client side) properly into rendered components by server. Thanks!
I have a ui.cljc file used by both client and server:
(ns dual.ui
(:require [rum.core :as rum :refer [defc]]))
(defn react [id]
#?(:clj @id
:cljs (rum/react id)))
(defc post-content [post]
[:div.post
...your code here...])
react
here is mostly used when the data has to be retrieved by an AJAX request, so I can just pass an atom that gets updated whenever the AJAX request finishes and it just works. On server-side, you pass in an atom or future. In this example, I am not passing atoms or using the react function since it’s not needed normally, but when you need it, it is there.
I use this file for HTML and some functions that are used by both client and server, but nothing specific to the client or to the server.
The server-side rendering is in views.clj:
(ns dual
(:require [dual.ui :as ui]
[rum.core :as rum]))
(defn post-page [post]
(rum/render-hml
[:html
[:body
[:div#post-id {:style "display: none"} (:id post)]
[:div#post-content-container (post-content post)]]])
I have my client code in admin_ui.cljs
(ns dual.admin-ui
(:require [domina :as d]
[dual.ui :as ui]
[reforms.rum :as f]
[rum.core :as rum :refer (defc defcs react)]))
(defc post-content
< rum/reactive
[post-atom]
(let [post (react post-atom)]
(ui/post-content post)))
When the ClojureScript runs, it grabs post-id from the div, does an AJAX request to get the post content as a map, setting post-atom’s value, and runs this callback:
(fn [_]
(rum/hydrate (post-content post-atom) (d/by-id "post-content-container"))
(render-post-editor post-atom))
render-post-editor
is just a form created by reforms that syncs to the post-atom, so whenever the form is changed, the displayed page updates to match it. The editor is side-by-side with the displayed page. For values that require DB lookups (say, if you wanted to show the “next post” title but the field provided is just the next post’s ID), you create an atom and write your ui.cljc code to use the react function. You do an AJAX request that updates the atom, and it renders correctly once complete (the relevant section will just be blank until then).
There is probably a cleaner way to do this, this is just something I got working on my first go and has been easy to extend/change when needed. reforms is very easy to set up and works brilliantly, and this is a fairly easy way to take advantage of it.