Using React.lazy with TypeScript
Asked Answered
C

7

39

I am trying to use React.lazy for code splitting in my TypeScript React app.

All I am doing is changing that line:

import {ScreensProductList} from "./screens/Products/List";

to this line:

const ScreensProductList = lazy(() => import('./screens/Products/List'));

But the import('./screens/Products/List') part triggers a TypeScript error, stating:

Type error: Type 'Promise<typeof import("/Users/johannesklauss/Documents/Development/ay-coding-challenge/src/screens/Products/List")>' is not assignable to type 'Promise<{ default: ComponentType<any>; }>'.
  Property 'default' is missing in type 'typeof import("/Users/johannesklauss/Documents/Development/ay-coding-challenge/src/screens/Products/List")' but required in type '{ default: ComponentType<any>; }'.

I am not quite sure what I am supposed to do here to get it to work.

Circumlunar answered 11/1, 2019 at 16:49 Comment(0)
P
77

You should do export default class {...} from the ./screens/Products/list instead of export class ScreensProductList {...}.

Or, alternatively, you can do:

const ScreensProductList = lazy(() =>
  import('./screens/Products/List')
    .then(({ ScreensProductList }) => ({ default: ScreensProductList })),
);
Postgraduate answered 15/1, 2019 at 9:31 Comment(6)
That works perfectly. And how would I go about lazy loading multiple none default exports from a module? Do I have to do the second approach for each export?Barbitone
@JohannesKlauß, yes, lazy() will only render a single component, so you have to repeat the wrapping for every one neededPostgraduate
That's really ugly. Especially since you can only have one default per module.Fluted
What types should be added to this for TypeScript?Inodorous
@JamesHancock you can check out my answer, react-lazily solves multiple components per module const { One, Two, Three } = lazily(() => import('./module'))Itself
@Inodorous this already has proper typescript types, you can see typescript example in codesandbox.io/s/react-lazily-vs-react-iqy23Itself
I
11

One option is to add default export in "./screens/Products/List" like that

export default ScreensProductList;

Second is to change import code to

const ScreensProductList = React.lazy(() =>
  import("./screens/Products/List").then((module) => ({
    default: module.ScreensProductList,
  }))
);

Or if you don't mind using an external library you could do:

import { lazily } from 'react-lazily';
const { ScreensProductList } = lazily(() => import('./screens/Products/List'));
Itself answered 2/12, 2020 at 0:33 Comment(0)
J
7

Another solution would be:

1. Import using lazy

const ScreensProductList = lazy(() => import('./screens/Products/List'));

2. Set the type on the export

React hooks

import { FunctionComponent /*, FC */ } from 'react';

const List = () => (
  return </>;
);

export default List as FunctionComponent; // as FC;

React class components

import { Component, Fragment, ComponentType } from 'react';

class List extends Component {
  render() {
    return <Fragment />;
  }
}

export default List as ComponentType;
Jacey answered 15/3, 2020 at 16:56 Comment(0)
M
3
const LazyCart = React.lazy(async () => ({ default: (await import('../Components/market/LazyCart')).LazyCart }))
Merrile answered 22/1, 2022 at 14:10 Comment(0)
O
1

This is the proper syntax. It works also in the Webstorm IDE (the other syntaxes shown here are still showing a warning)

const ScreensProductList = React.lazy(() => import("./screens/Products/List").then(({default : ScreensProductList}) => ({default: ScreensProductList})));
Ogle answered 14/9, 2021 at 15:15 Comment(0)
G
1

Just to expand on this answer. This also works for the dynamic imports.

const Navbar = dynamic(() => import('../components/Navbar'), {
  ssr: false,
});

Where Navbar is a default exported component.

const Navbar = () => ()


export default Navbar
Gilkey answered 26/1, 2023 at 12:8 Comment(0)
S
0

You can create an index.ts file where you can export all your components like in this eg. :

export {default as YourComponentName} from "./YourComponentName";

After that you can use React.lazy:

React.lazy(() => import("../components/folder-name-where-the-index-file-is-created").then(({YourComponentName}) => ({default: YourComponentName})))
Sheenasheeny answered 30/5, 2019 at 8:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.