5

I have a problem with combining React lazy with my project that uses TypeScript and Redux. Here is my code:

// lazy-area.tsx
const LazyArea = ({text}: Props): JSX.Element => {
    ....
};

export const LazyArea = connect(
mapStateToProps,
mapDispatchToProps
)(LazyArea);


//Menu.tsx
import React, { lazy, Suspense } from 'react';
....
const lazyArea = lazy(() => import('./lazy-area'));

const Menu = ({
    .....
  }: Props): JSX.Element | null => {
      return (
        <Suspense fallback={LoadingView}>
            <LazyArea />
        </Suspense>
      )
    export const Menu = connect(
    mapStateToProps,
    mapDispatchToProps
    )(Menu);
});

With this set up I get an error saying:

Type 'Promise<typeof import("/home/user/app/lazy-area")>' is not assignable to type 'Promise<{ default: ComponentType<any>; }>'.
  Property 'default' is missing in type 'typeof import("/home/user/app/src/lazy-area")' but required in type '{ default: ComponentType<any>; }'.

I have tried solutions presented in: TypeScript with React Lazy getting promise error to add export as ComponentType<any> and export as React.FC to LazyArea export but error stays the same.

The solution presented in here removes the error but according to this the solution is def not best practice and "may kill optimizations and potentially result in infinite loop".

This error also goes away when using export default in LazyArea:

const LazyArea = connect(
mapStateToProps,
mapDispatchToProps
)(LazyArea);

export default LazyArea;

However I have read from some sources that using export default should be avoided.

Is there any good solution to get past this problem? Please inform if I have presented too little info about something. Thanks :)

  • 2
    The sad truth is React.lazy in the current state intended to work only with default exports. Any way you trying to do it - is a hacky workaround to pretend we have a default export. The hacky workaround which is considered the best for now mentioned in the docs itself (https://reactjs.org/docs/code-splitting.html#named-exports) – Daydreaming Duck Apr 22 '20 at 16:48
  • alright, I guess using default export will just have to do then. Thanks :) – Anni Puurunen Apr 23 '20 at 08:19
  • Nice first question! – Jared Smith Dec 06 '20 at 21:02

1 Answers1

2

I don't know why you think using default exports should be avoided :) I think it's just a convention that some teams have. So adding export default LazyArea; is a valid way to deal with this. You won't have too many lazy modules anyway.

That's why the solution from React docs could also work where you just put that default export into its own file.

The other recommended approach is to change import code to convert it to default inline:

const LazyArea = React.lazy(() =>
  import("./lazy-area").then((module) => ({
    default: module.LazyArea,
  }))
);

But that's seems like too much work for me :) So I created react-lazily which does what you would expect.

Example

const { LazyArea } = lazily(() => import('./lazy-area'));

it's just a small wrapper around React.lazy, but it allows you to have a really straight forward code, like that:

import { lazily } from 'react-lazily';
const { Component1, Component2 } = lazily(() => import('./Components'))
JLarky
  • 9,833
  • 5
  • 36
  • 37