reagent

Vladimir Pouzanov 2024-12-19T16:56:23.717939Z

I'm looking for some advice on what am I doing wrong ๐Ÿ™‚ basically, refresh-on-save is broken for me sometimes and I can't figure the pattern on when it breaks. I have a re-frame/reagent/shadow-cljs stack. I have some trivial components like this

(defn account-info [name currency currency-token balance]
  [:div {:class "text-center pt-20 pb-20"}
   [:div {:class "flex items-center justify-center space-x-2"}
    [:span {:class "text-gray-300 font-medium"} (str name " ยท " currency)]]
   [:div {:class "mt-2 text-4xl font-bold text-active"} (str currency-token " " balance)]
   [:a {:href (rfe/href :accounts-list)}
    [:button {:class "btn mt-6 btn-lg btn-primary btn-soft rounded-full"} "Accounts"]]])
where commenting out anything would result in immediate refresh. But then I have components like
(defn account-card []
  (let [loading? @(rf/subscribe [:accounts/loading?])
        error @(rf/subscribe [:accounts/error])
        current-account @(rf/subscribe [:accounts/current-account])
        current-account-idx @(rf/subscribe [:accounts/current-account-idx])
        accounts-count @(rf/subscribe [:accounts/count])
        previous-route-back (-> @(rf/subscribe [:routes/previous-route]) :data :back)]
    [:div {:class ["flex flex-col"
                   (when (= previous-route-back :home) "animate-slideInLeft")]}
     (if loading?
       [:div {:class "flex items-center justify-center h-40"}
        [:span.loading.loading-spinner.loading-lg]]
       [:<>
        [account-info
         (:name current-account)
         (:currency current-account)
         (:currencyCode current-account)
         (:balance current-account)]
        [pagination accounts-count current-account-idx]])
     [toolbar current-account]
where changing it would require a full page reload before I see it. My understanding of going through https://day8.github.io/re-frame-wip/reusable-components/#re-frame-components is that re-frame components are reagent form-1 components, but, in practice, if I either wrap the hiccup of the account-card in a fn or do that and move the let inside it, nothing seems to change. What am I doing wrong?

โœ… 1
p-himik 2024-12-19T17:08:04.320969Z

I really don't like the term "re-frame component". Re-frame has nothing to do with components themselves. It only provides stuff that can be used from Reagent components - subscribe and dispatch. And any Reagent component can use that stuff - form-1, form-1 with r/with-let, form-2, form-3. As for what you're doing wrong - nothing that's in the code that you've provided. How is account-card used?

Vladimir Pouzanov 2024-12-19T17:10:06.997809Z

account-card is stored in the routes:

(def routes
  [["/"
    {:name :home
     :view accounts/account-card
     :auth :required}]
  ...
which is rendered via
(defn router-component []
  (when-let [current-route @(rf/subscribe [:routes/current-route])]
    [chrome (-> current-route :data :view)]))

...

(defn ^:dev/after-load mount-root []
  (rf/clear-subscription-cache!)
  (rdomc/render @react-root [:> react/StrictMode {} [routes/router-component]]))

Vladimir Pouzanov 2024-12-19T17:11:35.246679Z

(the router is reitit)

p-himik 2024-12-19T17:12:20.645869Z

How is the :routes/current-route sub implemented?

Vladimir Pouzanov 2024-12-19T17:13:41.329929Z

(rf/reg-sub
 :routes/current-route
 (fn [db _]
   (:current-route db)))

Vladimir Pouzanov 2024-12-19T17:16:04.054709Z

when I save the file the component clearly reloads:

p-himik 2024-12-19T17:17:18.261689Z

So you store the actual view function in app-db. Stop doing that and the problem will go away. Instead, you can store the name of the route there and resolve the route data via the routes var.

Vladimir Pouzanov 2024-12-19T17:18:48.717979Z

oh huh, thanks! it actually makes sense when you put it that way ๐Ÿ™‚

๐Ÿ˜‰ 1
Vladimir Pouzanov 2024-12-19T17:21:16.203279Z

yep, rewriting it as

["/"
    {:name :home
     :view #'accounts/account-card
     :auth :required}]
and [chrome @(*->* current-route :data :view)] totally fixed it.

p-himik 2024-12-19T17:22:36.661309Z

Eh, you're still storing the var in app-db. Just don't store any code-related things in app-db, your life will be easier. Otherwise, it's a recipe for some weird shit happening down the road.

Vladimir Pouzanov 2024-12-19T17:24:12.400619Z

ah. I see your point. Curiously, it's how the "easy" tutorial for reitit looks like: https://github.com/metosin/reitit/blob/master/examples/frontend/src/frontend/core.cljs

p-himik 2024-12-19T17:24:17.426869Z

Storing only data there (or relying on data as much as possible) is also much more flexible and lets you use re-frame to a fuller extent. Just an example - whenever an error happens on the user end, I dump the whole app-db and send it to the server. Then, I can use that data to view the state of the app exactly when the error happened.

p-himik 2024-12-19T17:24:51.311219Z

Curiously, it's how the "easy" tutorial for reitit looks likeBut it doesn't use re-frame, so I'm not sure what you mean.

p-himik 2024-12-19T17:25:46.885429Z

Ah, it has (defonce match (r/atom nil)) that's similar to re-frame's app-db. Yep, it will suffer from the same hot code reload issue.

Vladimir Pouzanov 2024-12-19T17:30:05.618849Z

> that's similar to re-frame's app-db yeah. I gonna go file them a bug for a discussion. Thanks again!

๐Ÿ‘ 1