Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Importing of an unknown component - NextJs

I want to load a component dynamically based on the route. I'm trying to make a single page which can load any individual component for testing purposes.

However whenever I try to do import(path) it shows the loader but never actually loads. If I hard code the exact same string that path contains then it works fine. What gives? How can I get nextjs to actually dynamically import the dynamic import?

// pages/test/[...component].js

const Test = () => {
  const router = useRouter();
  const { component } = router.query;
  const path = `../../components/${component.join('/')}`;

  console.log(path === '../../components/common/CircularLoader'); // prints true

  // This fails to load, despite path being identical to hard coded import
  const DynamicComponent = dynamic(() => import(path), {
    ssr: false,
    loading: () => <p>Loading...</p>,
  });

  // This seems to work
  const DynamicExample = dynamic(() => import('../../components/Example'), {
    ssr: false,
    loading: () => <p>Loading...</p>,
  });

  return (
    <Fragment>
      <h1>Testing {path}</h1>
      <div id="dynamic-component">
        <DynamicComponent />      <!-- this always shows "Loading..." -->
        <DynamicExample /> <!-- this loads fine. -->
      </div>
    </Fragment>
  );
};

export default Test;
like image 569
justin.m.chase Avatar asked Jul 16 '20 20:07

justin.m.chase


People also ask

How do I set up Dynamic imports in next JS?

Setting up dynamic imports in Next.js can be done in a few lines of code that are demonstrated in the example below. For more advanced ways to use the dynamic function, make sure to check out the Next.js Dynamic Imports. First, import the dynamic function using import dynamic from "next/dynamic";.

How do I import a dynamic component into an existing page?

Open the pages/index.js file and add an import for dynamic from next/dynamic at the beginning of the file: We can now import it as a dynamic component by adding the following at the beginning of the file: CodeSampleModal will be the default component returned by ../components/CodeSampleModal.

Why import() has to be inside the dynamic() call for next?

Furthermore the import () has to be inside the dynamic () call for Next.js to be able to match webpack bundles / module ids to the specific dynamic () call and preload them before rendering. dynamic () can't be used inside of React rendering as it needs to be marked in the top level of the module for preloading to work, similar to React.lazy.

What are Dynamic imports?

What are Dynamic Imports? Unlike regular import modules, dynamic imports are flexible about when and how they are loaded. Instead of being forced to load the module file at read time, dynamic imports can be requested at the time of use.


Video Answer


2 Answers

I put dynamic outside of the component, and it work fine.

const getDynamicComponent = (c) => dynamic(() => import(`../components/${c}`), {
  ssr: false,
  loading: () => <p>Loading...</p>,
});

const Test = () => {
  const router = useRouter();
  const { component } = router.query;
  
  const DynamicComponent = getDynamicComponent(component);

  return <DynamicComponent />
}
like image 119
bcjohn Avatar answered Sep 21 '22 11:09

bcjohn


I had the same issue like the thread opener. The Documentation describe, that it's not possible to use template strings in the import() inside dynamic: enter image description here

In my case it was also impossible to add an general variable with the path there...

Solution

I've found an easy trick to solve this issue:

// getComponentPath is a method which resolve the path of the given Module-Name
const newPath = `./${getComponentPath(subComponent)}`;
const SubComponent = dynamic(() => import(''+newPath));

All the MAGIC seems to be the concatenation of an empty String with my generated Variable newPath: ''+newPath

Another Solution:

Another Solution (posted by bjn from the nextjs-Discord-Channel):

const dynamicComponents = {
  About: dynamic(() => import("./path/to/about")),
  Other: dynamic(() => import("./path/to/other")),
  ...
};

// ... in your page or whatever
const Component = dynamicComponents[subComponent];
return <Component />

This example might be useful, if you know all dynamically injectable Components. So you can list them all and use it later on in your code only if needed)

like image 41
suther Avatar answered Sep 20 '22 11:09

suther