Do you want to request a feature or report a bug?
Feature
What is the current behavior?
Currently, React.lazy only accepts an anonymous function that returns a dynamic import object. readLazyComponentType
then pulls the default export off of that import object. This does not allow for importing named imports from a module.
The official workaround, according to the React docs:
If the module you want to import uses named exports, you can create an intermediate module that reexports it as the default.
Another, more concise workaround:
const Contacts = React.lazy(() =>
import('./Contacts.js').then(module => ({ default: module.Contacts }))
);
What is the proposed behavior?
I'd be willing to submit a PR that optionally accepts named imports but defaults to importing the default import. It would look like:
thenable.then(
- moduleObject => {
+ resolvedComponent => {
if (lazyComponent._status === Pending) {
- const defaultExport = moduleObject.default;
+ if (resolvedComponent.default) {
+ resolvedComponent = resolvedComponent.default
+ }
if (__DEV__) {
- if (defaultExport === undefined) {
+ if (resolvedComponent === undefined) {
warning(
false,
- 'lazy: Expected the result of a dynamic import() call. ' +
+ 'lazy: Expected a promise that resolves to a React component. ' +
'Instead received: %s\n\nYour code should look like: \n ' +
"const MyComponent = lazy(() => import('./MyComponent'))",
- moduleObject,
+ resolvedComponent,
);
}
}
lazyComponent._status = Resolved;
- lazyComponent._result = defaultExport;
+ lazyComponent._result = resolvedComponent;
}
},
error => {
if (lazyComponent._status === Pending) {
lazyComponent._status = Rejected;
lazyComponent._result = error;
}
},
);
This will also require some updates to the docs.
Let me know your thoughts before I start...
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
[email protected], Chrome 71, macOS 10.14
cc @acdlite @gaearon
Thanks but it's an intentional design decision to not currently allow named imports. We may reconsider it later. You can find the relevant discussion in https://github.com/reactjs/rfcs/pull/64.
This may seem stupid but I expected the feature to have the following syntax:
React.lazy('./MyComponent');
No more extra function or import
required
This may seem stupid but I expected the feature to have the following syntax:
React.lazy('./MyComponent');
No more extra function or
import
required
It's not working, but I have tried this ->
React.lazy(() => import('../MyComponent'), 'default');
It works fine!
This makes SFC components pretty annoying to use...
Summary of why named exports are not baked in and a workaround can be found in https://github.com/reactjs/rfcs/pull/64#issuecomment-431507924
npm audit
said I needed to update to react-scripts 4.0.0 as the only solution to a vulnerability. After upgrade, new ESLint rules went into effect warning about default exports. So, I removed all my default exports and replaced them with named. Now, my router doesn't work.
Thanks so much for not supporting this and making things harder on me. Probably time to reconsider this issue and the comment linked to in the previous comment.
Working with default exports on Function Components is very inconvenient. I hope the React team can revisit this soon. IMO React.lazy
is a very powerful tool, so I created a small abstraction of @gnestor's workaround to make the lazy import a bit simpler. When used with TypeScript it's 100% type-safe and keeps the look and feel of named imports. I hope this helps! 馃檪
function lazyImport<
T extends React.ComponentType<any>,
I extends { [K2 in K]: T },
K extends keyof I,
>(
factory: () => Promise<I>,
name: K
): I {
return Object.create({
[name]: React.lazy(() => factory().then(module => ({ default: module[name] })))
});
}
// Usage
const { Home } = lazyImport(() => import("./Home.component.tsx"), "Home");
PS: The Object.create(..)
is to avoid conflicts with the object key and the K
type. Another way would be to cast the object as unknown as I
, but I think this looks a bit cleaner that way 馃檪
Most helpful comment
Working with default exports on Function Components is very inconvenient. I hope the React team can revisit this soon. IMO
React.lazy
is a very powerful tool, so I created a small abstraction of @gnestor's workaround to make the lazy import a bit simpler. When used with TypeScript it's 100% type-safe and keeps the look and feel of named imports. I hope this helps! 馃檪PS: The
Object.create(..)
is to avoid conflicts with the object key and theK
type. Another way would be to cast the objectas unknown as I
, but I think this looks a bit cleaner that way 馃檪