// 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 |
This comment has been minimized.
This comment has been minimized.
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 |
This comment has been minimized.
This comment has been minimized.
Instead of using the |
This comment has been minimized.
This comment has been minimized.
Thanks, this was very helpful. I am still on webpack 1, therefore stick with Using it with React Router v4 and it's fine. |
This comment has been minimized.
This comment has been minimized.
Just came across this. Nice. :) I created a lib to help. Similar in concept, but different. |
This comment has been minimized.
This comment has been minimized.
How could I animate transitions when using asyncComponent for pages? |
This comment has been minimized.
This comment has been minimized.
@acdlite How do you handle system.import problem with nested routes? webpack/webpack-dev-server#333 Given
Will get |
This comment has been minimized.
This comment has been minimized.
Should this now use |
This comment has been minimized.
This comment has been minimized.
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... |
This comment has been minimized.
This comment has been minimized.
@acdlite does not work for me unless I type the extensions.
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.
How can I make this work without errors? |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
For server side rendering the AsyncComponent has a diferrent behaviour on the server than on the client. On the client, the asyncomponent always return null for the first time, than it finds/loads the component itself on the second time it renders. But on the server it will only return null on the first request! On the second request the server already know where the code splitted bundle is and immediatly return the component. Making react angry and complaining abour reused markup. A workaround is quite simple. asyncComponent has to always return null/(whatever you want) at server side. But this is not search engine friendly and I miss the whole point of server render
|
This comment has been minimized.
This comment has been minimized.
Thanks, very helpful :) |
This comment has been minimized.
This comment has been minimized.
@acdlite What's the reason that you're checking Great work on this BTW, very helpful. |
This comment has been minimized.
This comment has been minimized.
@mrmckeb The state is initialize with the static value |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@acdlite I get the following error message, any suggest for it?
|
This comment has been minimized.
This comment has been minimized.
thank you :) |
This comment has been minimized.
This comment has been minimized.
How would you go about tackling nested routes without having System.import for each of them? What if I wanted to group a couple of routes and have the parent load the bundle? Because component={} would require a loaded reference I'm having difficulty getting this to work, and out of the box V4 does not support the asynchronous loading of routes so that I could load them in from the bundle. Having trouble wrapping my head around this one :) most examples only have basic routes like /about, but what if you wanted /user, and /user/:id, and /user/:id/contact let's say? |
This comment has been minimized.
This comment has been minimized.
In react 15.4.2 i have a warning: |
This comment has been minimized.
This comment has been minimized.
@Slavenin use https://github.com/thejameskyle/react-loadable/ |
This comment has been minimized.
This comment has been minimized.
Sorry if this is a dumb question but where does come from? Is this an old react-routerism that no longer exists? |
This comment has been minimized.
This comment has been minimized.
Hey Andrew @acdlite can u please give clue to do server side rendering along with the code splitting with RRv4 |
This comment has been minimized.
This comment has been minimized.
Thank you for this brilliant code. I've been using this code very usefully. Since Additionally, rather than doing Full Code: function asyncComponent(getComponent) {
return class AsyncComponent extends React.Component {
static Component = null;
state = { Component: AsyncComponent.Component };
componentWillMount() {
if (!this.state.Component) {
getComponent().then(({default: Component}) => {
AsyncComponent.Component = Component
this.setState({ Component })
})
}
}
render() {
const { Component } = this.state
if (Component) {
return <Component {...this.props} />
}
return null
}
}
}
const Foo = asyncComponent(() => import('./Foo'))
const Bar = asyncComponent(() => import('./Bar')) |
This comment has been minimized.
This comment has been minimized.
@ashuorg, It is simple. Do not implement code splitting for server side rendering. Why would you need code splitting for SSR? You can implement code splitting only for the production build by using webpack.NormalModulesReplacementPlugin as: new webpack.NormalModuleReplacementPlugin(
/^pages$/,
'pages/index.async.js'
), For more details, check this out: https://medium.com/@apostolos/server-side-rendering-code-splitting-and-hot-reloading-with-react-router-v4-87239cfc172c |
This comment has been minimized.
This comment has been minimized.
@acdlite, is there any idea on loading the asyncComponent related reducers together, and inject the reducers into the store?
|
This comment has been minimized.
This comment has been minimized.
@acdlite, thanks for you solution it's working perfectly. |
This comment has been minimized.
This comment has been minimized.
Will the component js file be loaded more than once if the component unmounted and mounted again in the case such as React router. In the case of the code is not splitted, one bundle.js file is loaded just once. |
This comment has been minimized.
This comment has been minimized.
Hello everyone! I'm using this code: import React from "react";
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect,
Match
} from "react-router-dom";
// import Bundle from "Bundle/Bundle";
// import PedidoApp from "bundle-loader?lazy!./PedidoApp";
// import PedidoForm from "bundle-loader?lazy!./pedidoform";
// getComponent is a function that returns a promise for a component
// It will not be called until the first mount
const asyncComponent = getComponent => {
return class AsyncComponent extends React.Component {
static Component = null;
state = { Component: AsyncComponent.Component };
componentWillMount() {
if (!this.state.Component) {
getComponent().then(({ default: Component }) => {
AsyncComponent.Component = Component;
this.setState({ Component });
});
}
}
render() {
const { Component } = this.state;
if (Component) {
return <Component {...this.props} />;
}
return null;
}
};
};
const PedidoApp = asyncComponent(() => import("./PedidoApp"));
const PedidoForm = asyncComponent(() => import("./pedidoform"));
class Root extends React.Component {
render() {
return (
<Router>
<div>
<Link to="/pedido-1">Pedido</Link>
<Link to="/pedido-1/add">Agregar</Link>
<Route pattern="/pedido-1" component={PedidoApp} />
<Route pattern="/pedido-1/add" component={PedidoForm} />
<Redirect path="*" to="/pedido-1" />
</div>
</Router>
);
}
}
export default Root; But it shows both components at the same time. How do I do in order to show Thank you |
This comment has been minimized.
This comment has been minimized.
Hello, I've implemented with recompose: import React from 'react'
import { lifecycle } from 'recompose'
export default getComponent => {
const setLifecycle = lifecycle({
state: {
Component: undefined,
},
componentWillMount() {
if (!this.props.Component) {
getComponent().then(Component => {
this.setState({ Component })
})
}
},
})
const AsyncComponent = props => {
const { Component, ...otherProps } = props
if (Component) {
return <Component {...otherProps} />
}
return undefined
}
return setLifecycle(AsyncComponent)
} |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Something like this won't work? |
This comment has been minimized.
This comment has been minimized.
After rendering route component on a server I have FOT because when React initializes app - asyncComponent renders null at first time! |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@aerosunilkumar, transpile using https://babeljs.io/docs/plugins/preset-stage-0/ |
This comment has been minimized.
This comment has been minimized.
Thanks for this awesome post, made my life lot easier :) |
This comment has been minimized.
This comment has been minimized.
@acdlite |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@budarin @AndreGajdos It's memoization. It's caching it for the next time the component is used. First time it will do the fetch. Every time thereafter it will already be there in the static Component field. |
This comment has been minimized.
This comment has been minimized.
I have the same question as @budarin. |
This comment has been minimized.
This comment has been minimized.
How we can add progress until component not import. |
This comment has been minimized.
This comment has been minimized.
@nateq314 This should only be necessary if you're using something other than webpack. Using webpack the module only gets fetched one time, even if you're not caching the component in the static field. How do I pass props to the lazy loaded component? I see that I'm currently using something like this:
The route entry looks like this:
|
This comment has been minimized.
This comment has been minimized.
Nice!!! I would use Other than that awesome! |
This comment has been minimized.
This comment has been minimized.
You have to use Either |
This comment has been minimized.
This comment has been minimized.
Hello! Writing an async component like this in TypeScript:
TypeScript complains on
|
This comment has been minimized.
This comment has been minimized.
so dirty and so good, bro |
This comment has been minimized.
This comment has been minimized.
Can't figure out why |
This comment has been minimized.