Dynamic Import and Lazy load React Components

I am trying to load a components inside of a Tab component for react. The Idea is have a json ( or better yaml) with this syntanx:

interface TabType {
    name: string;
    components: string[];
}

interface Templates {
    tabs: TabType[];
}

const templateTabsModules: Templates = {
    tabs: [
        {
            name: "Title for Tab 1",
            components: ["./components/OneComponent"]
        },
        {
            name: "Title for Tab 2",
            components: ["./components/TwoComponent"]
        }
    ]
};

So inside of the Main Component do something like:

<Tabs id="tab">
   {templateTabsModules.tabs.map(tab => {
      return (
        <Tab title={tab.name}>
          <p>The component should appears bellow:</p>
          <Suspense fallback={<div>Loading</div>}>
           {tab.components.map(component => {
              const Comp = lazy(() => import(component));
              return (<Comp />)
           })}
          </Suspense>
         </Tab>
       );
    })}
</Tabs>

But this code does not work, I could see that if I use just the path as string by doing const Comp = lazy(() => import('./components/OneComponent')); it works, but does not if I use the dynamic variable.

Upvotes: 5

Views: 2707

Answers (2)

I found a possible solution that does what I need without declare before the components by doing:

<Tabs id="tab">
  {templateTabsModules.tabs.map((tab, index) => {
     return (
        <Tab title={tab.name} key={index}>
            <p>The component should appears bellow:</p>
            <Suspense fallback={<div>Loading</div>}>
             tab.components.map(component => {
               const Comp = lazy(() => import(
                 /* webpackChunkName: "my-chunk-name" */
                 /* webpackMode: "lazy" */
                 `${component}`
               ).then(comp => comp));

               return (<Comp />)

             })}
            </Suspense>
        </Tab>
      );
   })}
</Tabs>

So Webpack can load the component and return it as promise

Example -> https://codesandbox.io/s/lazy-components-with-react-mix9y

Upvotes: 5

Jonathan Irwin
Jonathan Irwin

Reputation: 5747

Webpack is trying it's best to exclude all the files that you don't need.

I think it should work if you define your consts before and reference them in your loop

const Comp1 = lazy(() => import('./components/OneComponent'));
const Comp2 = lazy(() => import('./components/TwoComponent'));

...

tabs: [
    {
        name: "Title for Tab 1",
        component: Comp1
    },
    {
        name: "Title for Tab 2",
        component: Comp2
    }
]

...

      <Suspense fallback={<div>Loading</div>}>
       {tabs.map(tab => tab.component)}
      </Suspense>

Upvotes: 3

Related Questions