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?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?
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]]))
(the router is reitit)
How is the :routes/current-route sub implemented?
(rf/reg-sub
:routes/current-route
(fn [db _]
(:current-route db)))
when I save the file the component clearly reloads:
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.
oh huh, thanks! it actually makes sense when you put it that way ๐
yep, rewriting it as
["/"
{:name :home
:view #'accounts/account-card
:auth :required}]
and [chrome @(*->* current-route :data :view)] totally fixed it.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.
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
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.
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.
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.
> that's similar to re-frame's app-db yeah. I gonna go file them a bug for a discussion. Thanks again!