Just a tip on how to use this library together with a HOC-loader like redux-connect:
// Your wrapped component
const MyAsyncComponent = loadable(() => import('./MyAsyncComponent/MyAsyncComponent'))
// Utility to extract the wrapped component if loadable-HOC will conflict with your other HOCs
const loadableWrapper = (cb, LoadableComponent) => {
LoadableComponent.load().then((Comp) => {
cb(null, Comp)
}).catch((error) => {
console.log('Error loading', error)
})
}
<Route path='/some-path' getComponent={(nextState, cb) => loadableWrapper(cb, MyAsyncComponent)} />
Later discovered that for SSR intial render we need to extract loadable-id and set a loadable key on the loaded component. If not the component would not be included in the script-tag, and you will have a flicker with nothing on the screen after intial SSR render while client-side is taking over. I use Preact and Preact-compat in production and it works fine now.
// Your wrapped component
const MyAsyncComponent = loadable(() => import('./MyAsyncComponent/MyAsyncComponent'))
// In your router-file
import { LOADABLE } from 'loadable-components/constants'
// Utility to extract the wrapped component if loadable-HOC will conflict with your other HOCs
const loadableWrapper = (cb, LoadableComponent) => {
LoadableComponent.load().then((Comp) => {
// Add LOADABLE-key and loadable-componentId to the component you send back to react-router (v3)
Comp[LOADABLE] = () => LoadableComponent
Comp.componentId = LoadableComponent.componentId
cb(null, Comp)
}).catch((error) => {
console.log('Error loading', error)
})
}
<Route path='/some-path' getComponent={(nextState, cb) => loadableWrapper(cb, MyAsyncComponent)} />
Thanks for this :)
@gerhardsletten you're rock! Do you work around with react loadable and this issue? I can't repeat the same behaviour.
The above code is with react-router v3, but with react-router v4 (and redux-connect) combining both the async Hoc and make the container lazyload is not possible. You need to re-organize your code having the Hoc above, and inside it lazyload the View with all heavy dendencies, like this:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { asyncConnect } from 'redux-connect'
import loadable from '@loadable/component'
import { isLoaded as isPageLoaded, load as loadPage } from 'redux/modules/page'
const PageView = loadable(() =>
import(/* webpackChunkName: "PageView" */'./PageView')
)
@asyncConnect([
{
promise: ({ store: { dispatch, getState }, location: { pathname } }) => {
const promises = []
if (!isPageLoaded(getState(), pathname)) {
promises.push(dispatch(loadPage(pathname)))
}
return Promise.all(promises)
}
}
])
@connect(
state => ({
page: state.page.data
})
)
export default class PageViewContainer extends Component {
render() {
return <PageView {...this.props} />
}
}
Hi.
Is this still the right way to work with asyncConnect'ed components? It seems like the load() method is not available on the loadable component.
Hi @jjblumenfeld
I just updated my latest commend from 9 august with the new scoped package-name for loadable.
Mark that the load-method is from my own projects redux-ducks modules, it return a promise used within @asyncConnect to reflect when the pages content is loaded
...
import { isLoaded as isPageLoaded, load as loadPage } from 'redux/modules/page'
Thanks. I am trying that now, it is not quite working yet for me. I am using react-router v3.2.1 and redux-connect v6.0.0, so I'm not sure if I should be using something more like the first example or the second one?
redux-connect just published v9 that supports [email protected] (new context api), maybe you need to update. Is it redux-connect and loading everything on server that is the problem, or is it the code-splitting that does not work?
I was able to get code-splitting working, but loading everything serverside
is not working for me.
On Tue, Mar 12, 2019 at 5:30 AM Gerhard Sletten notifications@github.com
wrote:
redux-connect just published v9 that supports [email protected] (new
context api), maybe you need to update. Is it redux-connect and loading
everything on server that is the problem, or is it the code-splitting that
does not work?—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/smooth-code/loadable-components/issues/15#issuecomment-471920281,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACAh5jJKRPmRobeqSbXwIlLV2UgXdNKCks5vV3OfgaJpZM4P-5bT
.
Its hard to tell you what you do wrong without seeing some code, please provide that and I will look into it. But in the server, its important to call redux-connects loadOnServer before ChunkExtractor from @loadable/server, and you can only do code-splitting below asyncConnect
Thanks again for your patient replies!
I found my issue. When I was re-factoring my code I had left some of the loadable/code-splitting code above an asyncConnect. I have re-factored it to put the asyncConnect around a wrapper which contains the loadable component as you had in your second example and it all works nicely now.
Great!
Hi @jjblumenfeld
I just updated my latest commend from 9 august with the new scoped package-name for loadable.
Mark that the load-method is from my own projects redux-ducks modules, it return a promise used within @asyncConnect to reflect when the pages content is loaded
... import { isLoaded as isPageLoaded, load as loadPage } from 'redux/modules/page'
Hey @gerhardsletten, can you please share what is inside your import { isLoaded as isPageLoaded, load as loadPage } from 'redux/modules/page'? I wan't to see how do you load the component.
I'm trying to solve Did not expect server HTML to contain a <div> in <div>. this problem for about a week already and no success. On server, I did everything correctly, put ChunkExtractor after loadOnServer.
On the client, I wrapped hydration with loadableReady, but whenever I add loadable to any route, it starts showing me the error above.
Here is the screenshot with the populated HTML from server

and this one is after hydration

this is our home page route, wrapped to our asyncConnectWithModifications which is same as asyncConnect

@gloompi Taking a look at your screenshot, and I think the connected Component needs to be a regular react-component and not a "loadable"-component, so if you add
const Home = loadable(() => import('./Home'))
// Insert this
const HomeContainer = (props) => {
return <Home {...props} />
}
And at the end you pass this HomeContainer:
)(HomeContainer)
@gerhardsletten I have tried this approach as well, but it didn't work. I still think that it's related to async load somehow, can you share what were doing inside the redux? Especially the loadPage action?
@gloompi Could you extract this into an example and share this on github? Getting it right with ssr also involves your babel-config, webpack setup and both your server.js and client.js entrypoint. Most likely you have something one places that cases this problem.
@gerhardsletten sure, I actually have opened an issue here https://github.com/gregberge/loadable-components/issues/633.
And there you can find all the examples with configs.
@gerhardsletten if it's not enough, I can try to create a repo with similar configs
@gloompi It would be great if you could extract a runable example
@gerhardsletten hey, glad to inform you that the new version of loadable/components solved my issue. Thank you for helping, really appreciate it❤️❤️❤️
@gloompi Great, all good debug-sessions starts with npm update ;-)
Most helpful comment
Later discovered that for SSR intial render we need to extract loadable-id and set a loadable key on the loaded component. If not the component would not be included in the script-tag, and you will have a flicker with nothing on the screen after intial SSR render while client-side is taking over. I use Preact and Preact-compat in production and it works fine now.