如果该文件存在,则动态导入 React 组件,否则显示默认消息

Posted

技术标签:

【中文标题】如果该文件存在,则动态导入 React 组件,否则显示默认消息【英文标题】:dynamically import a React Component if that file exists, otherwise show a default message 【发布时间】:2019-04-18 23:06:48 【问题描述】:

如果文件存在,我想有条件地导入 React 组件,如果不存在,则执行其他操作。例如显示默认视图或消息。

我试过了:

let Recipe;
try 
  Recipe = require(`docs/app/Recipes/$props.componentName`);
 catch (e) 
  Recipe = () => <div>Not found</div>;

但是 linter 抱怨我不应该尝试动态地要求文件,而是使用字符串文字。

对于我想要实现的目标,是否有更简洁的方法?

【问题讨论】:

【参考方案1】:

其实是有的。随着最近发布的 React v16.6.0 "lazy code splitting" 被引入。这就是它的工作原理,它与reacts''suspense'一起使用很有意义:

 import React, lazy, Suspense from 'react';
 const Recipe = lazy(() =>import(`./docs/app/Recipes/$props.componentName`));

    function SomeComponent() 
      return (
        <Suspense fallback=<Spinner/>>
          <Recipe />
        </Suspense>
      );
    

要处理找不到组件的情况,您可以使用Error Boundaries。你可以像这样用它来包装你的组件:

<ErrorBoundary>
  <Suspense fallback=<Spinner/>>
    <Recipe />
  </Suspense>
</ErrorBoundary>

最好直接在我上面链接的 react 文档上阅读更多相关信息。

【讨论】:

【参考方案2】:

问题在于这种方法会破坏包优化并将docs/app/Recipes/ 中的所有文件包含到包中,即使它们没有被使用。

更好的写法是使用&lt;React.Suspense&gt;React.lazy

const Recipe = React.lazy(() =>
  import(`docs/app/Recipes/$props.componentName`)
  .catch(() => ( default: () => <div>Not found</div> ))
);

用作:

<React.Suspense fallback='loading...'><Recipe/></React.Suspense>

一个更简洁的方法来做到这一点并避免 linter 错误是有一个可能组件的映射:

import Foo from 'docs/app/Recipes/Foo';
import Bar from 'docs/app/Recipes/Bar';
...

const componentsMap =  Foo, Bar ;

...

const Recipe = componentsMap[props.componentName] || () => <div>Not found</div>;

在这种情况下,props.componentName 可以根据需要进行验证。

【讨论】:

以上是关于如果该文件存在,则动态导入 React 组件,否则显示默认消息的主要内容,如果未能解决你的问题,请参考以下文章

React组件渲染

Webpack 检查文件是不是存在并在条件下导入

[react] 怎样动态导入组件?

react生命周期函数

根据配置条目在 React 中动态导入组件

React 动态菜单