lilactown / helix

A simple, easy to use library for React development in ClojureScript.
Eclipse Public License 2.0
627 stars 52 forks source link

React Refresh with JSValue #85

Closed lilactown closed 2 years ago

lilactown commented 3 years ago

Currently, using a JS tagged literal i.e. #js [] inside of a hook will bust the react-refresh cache every time.

This is due to the fact that #js [] emits a value created via deftype, and then helix coverts this at compile time to a string to use as the cache key. The stringified object contains a memory reference, which is different every time.


Copying @SevereOverfl0w 's slack investigation here for posterity:

dominicm 1:09 PM Ah, string/join runs in clojure-lang. Derp! Right, I bet it's getting something that looks very different then!

dominicm 1:10 PM "hooks-key" "(hooks/use-state (do #object[cljs.tagged_literals.JSValue 0x73ca9fc4 \"cljs.tagged_literals.JSValue@73ca9fc4\"] \"Lisa\"))" That's why! It's printing out the object using the JSValue, which is an object so has a memory reference associated @Alex J Henderson @lilactown here's the bug :smile:

dominicm 1:21 PM (string/join (map cljs.compiler/emit-constant hooks)) does the trick. But it's pretty verbose. Based on a cursory look around the source, you might only need to solve for regex/JSValue (based on the fact those are both things that broke Cljs' own caching in the past, and are still the only 2 custom ones: https://github.com/clojure/clojurescript/blob/9d3dfc369a01b31244eb925fef4c9fafa3824e24/src/main/clojure/cljs/analyzer.cljc#L94-L103). As far as I can tell, JSValue is the only deftype in a cljc file in ClojureScript, so special casing JSValue probably makes sense.

(string/join
  (clojure.walk/postwalk
    (fn [x]
      (if (instance? JSValue x)
        (str "#js" (.val x) "")
        x))
    hooks))

Also works if you just special case JSValue types. (edited)

lilactown commented 2 years ago

Fixed in https://github.com/lilactown/helix/commit/4cfe1857712f82756473fc02cc45ce147d0bbcd6