Product
Introducing Ruby Support in Socket
Socket is launching Ruby support for all users. Enhance your Rails projects with AI-powered security scans for vulnerabilities and supply chain threats. Now in Beta!
react-async-component
Advanced tools
Create Components that resolve asynchronously, with support for server side rendering and code splitting.
Create Components that resolve asynchronously, with support for server side rendering and code splitting.
const AsyncProduct = createAsyncComponent({
resolve: () => import('./components/Product'))
});
<AsyncProduct productId={1} /> // 🚀
This library is an evolution of code-split-component
. Unlike code-split-component
this library does not require that you use either Webpack or Babel. Instead it provides you a pure Javascript/React API which has been adapted in a manner to make it generically useful for lazy-loaded Components, with support for modern code splitting APIs (e.g import()
, System.import
, require.ensure
).
Firstly, you need to use our helper to allow your application to use asynchronous components in an efficient manner.
import { withAsyncComponents } from 'react-async-component'; // 👈
const app = <MyApp />;
// 👇
withAsyncComponents(app) // returns a Promise
.then((result) => {
ReactDOM.render(
// We return a new version of your app that supports
// asynchronous components.
result.appWithAsyncComponents, // 👈
document.getElementById('app')
);
});
Next up, let's make an asynchronous Component! We provide another helper for this.
import { createAsyncComponent } from 'react-async-component'; // 👈
const AsyncProduct = createAsyncComponent({
// Provide a function that returns a Promise to the target Component.
resolve: function resolveComponent() {
return new Promise(function (resolve) {
// The Promise the resolves with a simple require of the
// `Product` Component.
resolve(require('./components/Product'));
});
}
});
// You can now use the created Component as though it were a
// "normal" Component, providing it props that will be given
// to the resolved Component.
const x = <Product productId={10} />
The above may look a tad bit verbose. If you are a fan of anonymous functions then we could provide a more terse implementation:
const AsyncProduct = createAsyncComponent({
resolve: () => new Promise(resolve =>
resolve(require('./components/Product'))
)
});
Okay, the above may not look terribly useful at first, but it opens up an easy point to integrating code splitting APIs supported by bundlers such as Webpack. We will provide examples of these as well as details on some other useful configuration options within the API
section.
createAsyncComponent(config)
Our async Component factory. Config goes in, an async Component comes out.
config
: Object
The configuration object for the async Component. It has the following properties available:
resolve
: Function => Promise
A function that should return a Promise
that will resolve the Component you wish to be async.defer
: Boolean (Optional, default: false)
Only useful for server side rendering applications. If this is set to true then the async component will only be resolved on the client/browser, not the server. I highly recommend that you consider using this value as much as you can. Try to relieve the load on your server and use server side rendering to provide an application shell for your users. They will still get a perceived performance benefit.Loading
: Component (Optional, default: null)
A Component to be displayed whilst your async Component is being resolved. It will be provided the same props that will be provided to your resovled async Component.es6Aware
: Boolean (Optional, default: true)
If you are using ES2015 modules with default exports (i.e export default MyComponent
) then you may need your Component resolver to do syntax such as require('./MyComp').default
. Forgetting the .default
can cause havoc with hard to debug error messages. To cover your back we will automatically try to resolve a .default
on the result that is resolved by your Component. If the .default
exists it will be used, else we will use the original result.A React Component.
const AsyncProduct = createAsyncComponent({
resolve: () => new Promise(resolve =>
resolve(require('./components/Product'))
)
});
<AsyncProduct productId={1} />
const AsyncProduct = createAsyncComponent({
resolve: () => new Promise(resolve =>
resolve(require('./components/Product'))
),
Loading: ({ productId }) => <div>Loading product {productId}</div>
});
<AsyncProduct productId={1} />
require.ensure
Code Splittingconst AsyncProduct = createAsyncComponent({
resolve: () => new Promise(resolve =>
require.ensure([], (require) => {
resolve(require('./components/Product'));
});
)
});
<AsyncProduct productId={1} />
import
/ System.import
Code SplittingNote: System.import
is considered deprecated and will be replaced with import
, but for now they can be used interchangeably (you may need a Babel plugin for the import
syntax).
const AsyncProduct = createAsyncComponent({
resolve: () => System.import('./components/Product')
});
<AsyncProduct productId={1} />
i.e. The component won't be resolved and rendered in a server side rendering execution.
const AsyncProduct = createAsyncComponent({
resolve: () => System.import('./components/Product'),
defer: true
});
withAsyncComponents(element)
Decorates your application with the ability to use async Components in an efficient manner. It also manages state storing/rehydrating for server side rendering applications.
app
React.Element
The react element representing your application.A promise that resolves in a result
object. The result
object will have the following properties available:
appWithAsyncComponents
React.Element
Your application imbued with the ability to use async Components. ❗️Use this when rendering your app.state
Object
Only used on the "server" side of server side rendering applications. It represents the state of your async Components (i.e. which ones were rendered) so that the server can feed this information back to the client/browser.STATE_IDENTIFIER
String
Only used on the "server" side of server side rendering applications. The identifier of the property you should bind the state
object to on the window
object.import React from 'react';
import { render } from 'react-dom';
import { withAsyncComponents } from 'react-async-component'; // 👈
import MyApp from './shared/components/MyApp';
const app = <MyApp />
// 👇 run helper on your app.
withAsyncComponents(app)
// 👇 and you get back a result object.
.then((result) => {
const {
// ❗️ The result includes a decorated version of your app
// that will allow your application to use async components
// in an efficient manner.
appWithAsyncComponents
} = result;
// Now you can render the app.
render(appWithAsyncComponents, document.getElementById('app'));
});
When using this helper on the "server" side of your server side rendering applications you should do the following.
Note: on the "client" side of a server side rendering application you can use the helper in the "nomral" fashion as detailed in the previous example.
import React from 'react';
import { withAsyncComponents } from 'react-async-component'; // 👈
import { renderToString } from 'react-dom/server';
import serialize from 'serialize-javascript';
import MyApp from './shared/components/MyApp';
export default function expressMiddleware(req, res, next) {
const app = <MyApp />;
// 👇 run helper on your app.
withAsyncComponents(app)
// 👇 and you get back a result object.
.then((result) => {
const {
// ❗️ The result includes a decorated version of your app
// that will have the async components initialised for
// the renderToString call.
appWithAsyncComponents,
// This state object represents the async components that
// were rendered by the server. We will need to send
// this back to the client, attaching it to the window
// object so that the client can rehydrate the application
// to the expected state and avoid React checksum issues.
state,
// This is the identifier you should use when attaching
// the state to the "window" object.
STATE_IDENTIFIER
} = result;
const appString = renderToString(appWithAsyncComponents);
const html = `
<html>
<head>
<title>Example</title>
</head>
<body>
<div id="app">${appString}</div>
<script type="text/javascript">
window.${STATE_IDENTIFIER} = ${serialize(state)}
</script>
</body>
</html>`;
res.send(html);
});
}
At the moment there is one known caveat in using this library: it doesn't support React Hot Loader (RHL). You can still use Webpack's standard Hot Module Replacement, however, RHL does not respond nicely to the architecture of react-async-component
.
TODO: I'll post up some details why and perhaps we could work to find a solution.
Let me know if you have any...
FAQs
Create Components that resolve asynchronously, with support for server side rendering and code splitting.
The npm package react-async-component receives a total of 2,207 weekly downloads. As such, react-async-component popularity was classified as popular.
We found that react-async-component demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socket is launching Ruby support for all users. Enhance your Rails projects with AI-powered security scans for vulnerabilities and supply chain threats. Now in Beta!
Product
Ensure open-source compliance with Socket’s License Enforcement Beta. Set up your License Policy and secure your software!
Product
We're launching a new set of license analysis and compliance features for analyzing, managing, and complying with licenses across a range of supported languages and ecosystems.