Fork me on GitHub
#reagent
<
2020-11-12
>
Andrew Watts05:11:40

I am having an issue and I'm not sure whose fault it is, whether that be the cljs compiler, reagent, or figwheel-main. It appears that sometimes when figwheel-main compiles reagent.impl.component/wrap-render, it generates invalid JS, and then when it loads one of my components which uses reagent.core/create-react-class, it errors out with the following error message:

Uncaught ReferenceError: sb__3001__auto__ is not defined
    reagent$impl$component$wrap_render component.js:186
    reagent$impl$component$do_render component.cljs:141
    render component.cljs:164
    reagent$ratom$in_context ratom.cljs:42
    reagent$ratom$deref_capture ratom.cljs:55
    reagent$ratom$run_in_reaction ratom.cljs:537
    reagent$impl$component$render component.cljs:164
    React 16
        finishClassComponent
        updateClassComponent
        beginWork
        callCallback
        invokeGuardedCallbackDev
        invokeGuardedCallback
        beginWork$1
        performUnitOfWork
        workLoopSync
        performSyncWorkOnRoot
        scheduleUpdateOnFiber
        updateContainer
        legacyRenderSubtreeIntoContainer
        unbatchedUpdates
        legacyRenderSubtreeIntoContainer
        render
    reagent$dom$render_comp dom.cljs:16
    cljs$core$IFn$_invoke$arity$3 dom.cljs:41
    reagent$dom$render dom.cljs:27
    cljs$core$IFn$_invoke$arity$2 dom.cljs:36
    reagent$dom$render dom.cljs:27
    dbn$frontend$core$main core.cljs:8
    <anonymous> core.cljs:13

Andrew Watts05:11:20

The function that's causing the problem is this one:

(defn wrap-render
  "Calls the render function of the component `c`.  If result `res` evaluates to a:
     1) Vector (form-1 component) - Treats the vector as hiccup and returns
        a react element with a render function based on that hiccup
     2) Function (form-2 component) - updates the render function to `res` i.e. the internal function
        and calls wrap-render again (`recur`), until the render result doesn't evaluate to a function.
     3) Anything else - Returns the result of evaluating `c`"
  [^clj c]
  (let [f (.-reagentRender c)
        _ (assert-callable f)
        ;; cljsLegacyRender tells if this calls was defined
        ;; using :render instead of :reagent-render
        ;; in that case, the :render fn is called with just `this` as argument.
        res (if (true? (.-cljsLegacyRender c))
              (.call f c c)
              (let [v (get-argv c)
                    n (count v)]
                (case n
                  1 (.call f c)
                  2 (.call f c (nth v 1))
                  3 (.call f c (nth v 1) (nth v 2))
                  4 (.call f c (nth v 1) (nth v 2) (nth v 3))
                  5 (.call f c (nth v 1) (nth v 2) (nth v 3) (nth v 4))
                  (.apply f c (.slice (into-array v) 1)))))]
    (cond
      (vector? res) (as-element res)
      (ifn? res) (let [f (if (reagent-class? res)
                           (fn [& args]
                             (as-element (apply vector res args)))
                           res)]
                   (set! (.-reagentRender c) f)
                   (recur c))
      :else res)))
and the generated JS is (after indenting)

Andrew Watts05:11:20

reagent.impl.component.wrap_render = (function reagent$impl$component$wrap_render(c){
  while(true){
    var f = c.reagentRender;
    var _ = ((cljs.core.ifn_QMARK_.call(null,f))?null:(function(){throw (new Error(["Assert failed: ",["Expected something callable, not ",cljs.core.pr_str.call(null,f)].join(''),"\n","(clojure.core/ifn? f)"].join('')))})());
    var res = ((c.cljsLegacyRender === true)?f.call(c,c):(function (){var v = reagent.impl.component.get_argv.call(null,c);
                                                                      var n = cljs.core.count.call(null,v);
                                                                      var G__31950 = n;
                                                                      switch (G__31950) {
                                                                        case (1):
                                                                          return f.call(c);

                                                                          break;
                                                                        case (2):
                                                                          return f.call(c,cljs.core.nth.call(null,v,(1)));

                                                                          break;
                                                                        case (3):
                                                                          return f.call(c,cljs.core.nth.call(null,v,(1)),cljs.core.nth.call(null,v,(2)));

                                                                          break;
                                                                        case (4):
                                                                          return f.call(c,cljs.core.nth.call(null,v,(1)),cljs.core.nth.call(null,v,(2)),cljs.core.nth.call(null,v,(3)));

                                                                          break;
                                                                        case (5):
                                                                          return f.call(c,cljs.core.nth.call(null,v,(1)),cljs.core.nth.call(null,v,(2)),cljs.core.nth.call(null,v,(3)),cljs.core.nth.call(null,v,(4)));

                                                                          break;
                                                                        default:
                                                                          return f.apply(c,cljs.core.into_array.call(null,v).slice((1)));

                                                                      }
                                                                     })());
    if(cljs.core.vector_QMARK_.call(null,res)){
      return reagent.impl.component.as_element.call(null,res);
    } else {
      if(cljs.core.ifn_QMARK_.call(null,res)){
        var f__$1 = ((reagent.impl.component.reagent_class_QMARK_.call(null,res))?((function (c,f,_,res,sb__3001__auto__,sbw__3002__auto__){
          return (function() { 
            var G__31952__delegate = function (args){
              return reagent.impl.component.as_element.call(null,cljs.core.apply.call(null,cljs.core.vector,res,args));
            };
            var G__31952 = function (var_args){
              var args = null;
              if (arguments.length > 0) {
                var G__31953__i = 0, G__31953__a = new Array(arguments.length -  0);
                while (G__31953__i < G__31953__a.length) {G__31953__a[G__31953__i] = arguments[G__31953__i + 0]; ++G__31953__i;}
                args = new cljs.core.IndexedSeq(G__31953__a,0,null);
              } 
              return G__31952__delegate.call(this,args);};
            G__31952.cljs$lang$maxFixedArity = 0;
            G__31952.cljs$lang$applyTo = (function (arglist__31954){
              var args = cljs.core.seq(arglist__31954);
              return G__31952__delegate(args);
            });
            G__31952.cljs$core$IFn$_invoke$arity$variadic = G__31952__delegate;
            return G__31952;
          })()
          ;})(c,f,_,res,sb__3001__auto__,sbw__3002__auto__))
                     :res);
        (c.reagentRender = f__$1);

        var G__31955 = c;
        c = G__31955;
        continue;
      } else {
        return res;

      }
    }
    break;
  }
});

Andrew Watts05:11:36

I assume this is in the function that gets returned from the then case of the (if (reagent-class? res) ...), and it's being declared with two parameters, sb__3001____auto__ and sbw__3002__auto__ , and the function is then being immediately called with those names, but they're not defined outside of the function, causing the error. But I don't know how to look further than this.

Andrew Watts05:11:24

It's also interesting to point out that this doesn't always occur. Sometimes it builds fine, but then if I recompile and reagent.impl.component gets recompiled (like when I do a figwheel reset), this error starts happening.

phronmophobic06:11:26

what version of reagent are you using, it seems like create-react-class was removed from reagent some time ago

Andrew Watts07:11:43

I'm using reagent 0.10. And that was a typo. It's using reagent.core/create-class. The component that's failing is borrowed from here: https://github.com/nberger/reagent-infinite-scroll/blob/master/src/cljs/reagent_infinite_scroll/scroll.cljs, though I've modified it slightly.