Anyone managed to get rum, code-splitting and React working?

clojurescript

#1

(cross-posted https://github.com/tonsky/rum/issues/186)

Hello,

I’m trying to integrate React.lazy and React.Suspense from React 16.6.0 with Rum in ClojureScript with code-splitting, and I’m failing hard. Basically I’m trying to do something like (everything is inlined for simplicity):

(rum/defc some-component
          []
          (js/React.createElement js/React.Suspense
                                  #js {:fallback (sablono.core/html [:h3 "PLACEHOLDER"])}
                                  (js/React.createElement (js/React.lazy (fn []
                                                                           (js/Promise. (fn [resolve-p reject-p]
                                                                                          (loader/load :popin
                                                                                                       (fn []
                                                                                                         (let [component (resolve 'yoda.components.popin-content/dummy)]
                                                                                                           (resolve-p (component))))))))))))


I’ve put many console.log and it clearly shows that the problem comes from where I resolve the promise (resolve-p (component)). All my attempts (which are variations of the code above) resulted in React telling me in the console that

“Object is not valid React child”

or

"Warning: lazy: Expected the result of a dynamic import() call. Instead received: #‘my-
app.components/dummy (Note: it’s the Var of the component)
Your code should look like:
const MyComponent = lazy(() => import(’./MyComponent’))

or

"Warning: lazy: Expected the result of a dynamic import() call. Instead received: [object Object]
Your code should look like:
const MyComponent = lazy(() => import(’./MyComponent’))

I’ve tried so many combinations of functions, rum/defc, (js/React.createElement ...) that I’ve lost count. Does someone here managed to get something working? Working solutions very appreciated.


#2

I haven’t tried this yet, but one thing to note is that React.lazy expects the resolved value of the promise your function returns to be a JS object, with your React component located in the default property.


#3

Solved: cljs.core/resolve returns a var you have to deref to get the rum constructor, and the underlying React component is stored under the :rum/class meta. So the last part of my code becomes:

(let [component (resolve 'yoda.components.popin-content/dummy)]
  (resolve-p #js {"default" (:rum/class (meta @component))}))

Thanks @tonsky for the pointer on Github.