【问题标题】:Dynamic Importing of an unknown component - NextJs未知组件的动态导入 - NextJs
【发布时间】:2020-11-06 14:18:36
【问题描述】:

我想根据路由动态加载组件。我正在尝试制作一个可以加载任何单个组件以进行测试的页面。

但是,每当我尝试执行 import(path) 时,它会显示加载程序,但从未实际加载。如果我硬编码 path 包含的完全相同的字符串,那么它可以正常工作。是什么赋予了?如何让 nextjs 实际动态导入动态导入?

// 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;

【问题讨论】:

    标签: next.js dynamic-import


    【解决方案1】:

    我遇到了和开线器一样的问题。 文档描述,不可能在 import() 内部动态中使用模板字符串:

    在我的情况下,也无法在此处添加带有路径的通用变量...

    解决方案

    我找到了一个简单的技巧来解决这个问题:

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

    所有 MAGIC 似乎都是一个空字符串与我生成的变量 newPath:''+newPath 的连接

    另一种解决方案:

    另一种解决方案(由 bjnnextjs-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 />
    

    如果您了解所有可动态注入的组件,此示例可能会很有用。 因此,您可以将它们全部列出并仅在需要时在您的代码中使用)

    【讨论】:

    • 第二种解决方案实际上对我有用,只是只有一大堆组件......添加它们会很烦人,但我认为这实际上是值得的。
    • 我找到的最佳解决方案,完美运行,没有警告。我问自己的唯一一点是,一次加载所有组件可能有点太重了。
    【解决方案2】:

    这是因为router.query 还没有准备好,而router.query.component 在动态页面的第一次呈现时是undefined

    这将在第一次渲染时打印false,在下一次渲染时打印true

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

    您可以用useEffect 包装它以确保已加载query

    const router = useRouter();
    
    useEffect(() => {
      if (router.asPath !== router.route) {
        // router.query.component is defined
      }
    }, [router])
    

    SO: useRouter receive undefined on query in first render

    Github Issue: Add a ready: boolean to Router returned by useRouter

    【讨论】:

      【解决方案3】:

      我将dynamic 放在组件之外,它工作正常。

      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 />
      }
      

      【讨论】:

      • 原来问题是因为 webpackn 查看导入中的字符串并根据它可以推断的路径打包文件。如果它完全是一个像我这样的表达式,则会发出警告并且没有任何反应。如果您像在../components/${c} 那样做,那么它将打包组件下的所有文件并且可以工作。但是在我的情况下,项目足够大,编译器会因 oom 而崩溃,所以基本上我无法进行基于表达式的导入。真让我吃惊。
      • 我想得到同样的东西,但我想要动态组件预渲染。然而,即使使用ssr:true,它也只是进行客户端渲染。有什么想法吗?
      • 如果你设置ssr:true,组件应该只在服务器端渲染。
      • 使用此解决方案在控制台上仍然会减弱。唯一适用的解决方案是来自@suther 的“另一种解决方案”。
      猜你喜欢
      • 1970-01-01
      • 2019-05-28
      • 1970-01-01
      • 1970-01-01
      • 2021-12-28
      • 2020-06-03
      • 2023-02-25
      • 2022-06-12
      • 1970-01-01
      相关资源
      最近更新 更多