I am experiencing an issue with hot reloading. I have a map of tab-names and components that looks like this:
(def component-spec
[{:tab :users
:component users/root}
{:tab :email
:component email/root}])
In a separate namespace, these components are passed along and called via into:
(into [section-component] component-args)
Changes made to users/root are are not being hot reloaded in the UI. This wasn’t an issue before updating React 16 to React 18 && shadow-cljs “2.23.3” to “2.28.20"
Were there any known changes that may have caused this?I don't recommend using vars since they generate a bunch of "noise" I wouldn't want in a release build. the anon functions achieve the same goal and will just be removed by :advanced, so no loss there
Sometimes a combination of a factory function and a more dynamic reference like #'users/root has got me unstuck with reloading
this has nothing to do with the shadow-cljs version and will have worked the exact same since hot-reload was added
so, hot-reload swaps the actual var at email/root. not the reference in the map, that holds on to whatever it was when the map was created
now if for whatever reason that map is NOT recreated by the hot-reload it will keep using the old reference
the default hot-reload mechanism only reloads namespaces that actually changed and then namespaces that directly depended on those that changed, not further
so depending on how things are structured this may not catch everything and have lingering references floating arround the system
what may have changed in react is that it decide to skip rendering early, since its arguments didn't change. as in the old reference is still the old reference rendering the old thing
basically the fix is to NOT hold onto other vars directly
what you can do is add anonymous functions, so instead of :component users/root you pass :component #(users/root %) (or however many args are passed to that component
this anonymous function can remain unchanged, but when called will look up and call the latest version of that var
react not rendering you'll have to sort for yourself, this is not something shadow-cljs has any hand in
best option is to just stick with data 😛 so only use {:tab :users} {:tab :email} and in the component rendering the stuff just do a (case tab :users (users/root ...) :email (email/root ...) ...). that will also never suffer any lingering references to old stuff
FWIW there is also :devtools {:reload-strategy :full} in the build config, which is kind of the nuclear option to always reload everything
will slow down hot reloads substantially, but usually fixes all sort of intermediate state
^that was the only thing that worked, but it didn’t seem ideal
I will try this stuff out - thank you so much for the response
It turns out the fix was the components (let’s call one Z for simplicity) were rendered in another namespace (let’s call it Y) in a component rendered by another namespace (let’s call it X) So the requires for Z and it’s sister components needed to be present in X (not Y). I was stuck on this for a long time, just wanted to pass along the info to anyone who might get use out of it.
so, the problem was react deciding it didn't need to re-render because Z didn't change (because shadow-cljs didn't recompile it)
adding the require adds it to the files that get recompiled. this isn't ideal because you are basically doing a slower version of :reload-strategy :full. as in force an actual recompiled, instead of just a reload 😛
^ that did work. It is a rather large application however, and it was a little painful so I’m glad to have found this fix 🙂
I'd expect so? I mean otherwise it just reloads the file, now it compiles and reloads it
so far it feels faster, but maybe I’m high on my own solution
best option is to make react just re-render the thing in some way