Create a gist now

Instantly share code, notes, and snippets.

@acdlite /app.js
Last active Jan 21, 2017

Quick and dirty code splitting with React Router v4
// getComponent is a function that returns a promise for a component
// It will not be called until the first mount
function asyncComponent(getComponent) {
return class AsyncComponent extends React.Component {
static Component = null;
state = { Component: AsyncComponent.Component };
componentWillMount() {
if (!this.state.Component) {
getComponent().then(Component => {
AsyncComponent.Component = Component
this.setState({ Component })
})
}
}
render() {
const { Component } = this.state
if (Component) {
return <Component {...this.props} />
}
return null
}
}
}
const Foo = asyncComponent(() =>
System.import('./Foo').then(module => module.default)
)
const Bar = asyncComponent(() =>
System.import('./Bar').then(module => module.default)
)
const App = () =>
<BrowserRouter>
<Link to="/foo">Foo</Link>
<Link to="/bar">Bar</Link>
<Match pattern="/foo" component={Foo} />
<Match pattern="/bar" component={Bar} />
</BrowserRouter>
export default App
@mhaagens
mhaagens commented Oct 5, 2016

Thanks so much for this! Would you happen to know a good way to be able to pass in props to the component? I.E. I used to be able to do render={(props) => <Home {...props} store={store} />}.

@lourd
lourd commented Oct 5, 2016

Instead of using the component prop for Match, use render or children.

@mcku
mcku commented Oct 11, 2016 edited

Thanks, this was very helpful. I am still on webpack 1, therefore stick with require.ensure instead of System.import. Addition of a wrapper around require.ensure helps async loading of modules, as shown on this link.

Using it with React Router v4 and it's fine.

@ctrlplusb

Just came across this. Nice. :)

I created a lib to help. Similar in concept, but different.

code-split-component

@strangegit

How could I animate transitions when using asyncComponent for pages?

@gutenye
gutenye commented Dec 4, 2016 edited

@acdlite How do you handle system.import problem with nested routes? webpack/webpack-dev-server#333

Given

<Match pattern="/foo/bar" component={Bar} />

Will get GET http://localhost:3000/foo/1.app.js 404 not found error. The correct path should be http://localhost:3003/1.app.js

@btnwtn
btnwtn commented Jan 6, 2017

Should this now use require.ensure instead of System.import?

@cloud-walker

I think this solution is elegant but too complicated to implement (same for the code-split-component solution...), I still don't get why react-router 4 won't handle the async routes on the server-side...

@cescoferraro
cescoferraro commented Jan 19, 2017 edited

@acdlite does not work for me unless I type the extensions.

const Foo = asyncComponent(() =>
  System.import('./Foo.tsx').then(module => module.default)
)

My problem is that I am using server side rendering, then on the server I require component A. on the client I System.import component A.
So when I access the lazy loaded route I get this react reuse markup warning because the client rendered
null from https://gist.github.com/acdlite/a68433004f9d6b4cbc83b5cc3990c194#file-app-js-L21
while loading Component A.

Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(client) CO 0.0.0<!-- react-empty: 6 -
(server) CO 0.0.0<div data-radium="tru

How can I make this work without errors?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment