React:动态导入JSX

6
这个问题与在React中动态导入JSX文件有关。 基本上,我们有一个主组件,根据存储在数据库中的结构动态地渲染其他组件。这些动态组件存储在子目录“./Components”中。我们静态地将它定义为:
import CompA  from './Components/CompA';
import CompB  from './Components/CompB';

var components = {
 'CompA': CompA,
 'CompB': CompB
}

我们使用以下方式进行呈现:
var type = 'CompA' 
var Component = components[type];
...
<Component />

尽管这可以很好地工作,但对我们而言有点过于静态。我们有100多个组件 (CompA/CompBs),静态定义它们是行不通的。
是否可以导入"./Components"中的所有JSX文件并填充组件数组?
而且,真正 (真正) 不错的是,如果我们可以将 "./Components" 路径作为属性发送到主组件,那将会如何呢?主组件将使用此路径来导入 .jsx 文件。像这样:
<MainComponent ComponentPath="./SystemComponents">

将"./SystemComponents"作为 .JSX 文件的路径,并:

<MainComponent ComponentPath="./UserComponents">

将使用"./UserComponents"作为导入路径。

3个回答

8
有一个 components/index.js 文件,其中包含以下内容:
export CompA from "./comp_a";
export CompB from "./comp_b";

然后你需要执行以下操作:
import * as Components from "./components"

那么你需要使用:

<Components.CompA />
<Components.CompB />
...

希望这有所帮助。 我怀疑当通过组件props发送路径时,您无法加载任何内容。文件的加载应在React组件生命周期方法中进行,但我不建议这样做。

1
不错!这个解决方案对我们来说真的非常有效。我们可以导入所有库(如上面示例中的不同路径),并将所需的库作为props传递。PS.由于某种原因,我无法让"./comp_a"中的export CompA正常工作,必须先导入它们,然后在json对象中导出它们。 - mathan
@mathan,一行代码的导出是 Babel 阶段-1 预设的一部分:export-extensions - Gabriel Bleu

1
截至React 16.6.0,我们可以延迟加载组件并按需调用它们。 路由
// We pass the name of the component to load as a param
<Switch>
  …
  <Route path="/somewhere/:componentName" component={MyDynamicComponent} />
</Switch>

views/index.js

import { lazy } from 'react';

const SomeView = lazy(() => import('./SomeView'));
const SomeOtherView = lazy(() => import('./SomeOtherView'));

export { SomeView, SomeOtherView };

MyDynamicComponent.js

import React, { Suspense, Component } from 'react';
import { PropTypes } from 'prop-types';
import shortid from 'shortid'; // installed separately via NPM
import * as Views from './views';

class MyDynamicComponent extends Component {
  render() {
    const {
      match: {
        params: { componentName },
      },
    } = this.props;

    const Empty = () => <div>This component does not exist.</div>;
    const dynamicComponent = (() => {
      const MyComponent = Views[`${componentName}View`]
        ? Views[`${componentName}View`]
        : Empty;
      return <MyComponent key={shortid.generate()} />;
    })();

    return (
      <>
        <Suspense fallback={<div>Loading…</div>}>{dynamicComponent}</Suspense>
      </>
    );
  }
}
MyDynamicComponent.propTypes = {
  match: PropTypes.shape({
    params: PropTypes.shape({
      componentName: PropTypes.string.isRequired,
    }),
  }),
};

export default MyDynamicComponent;

使用方法

{items.map(item => (
  <NavLink to={`/somewhere/${item.componentName}`}>
    {item.name}
  </NavLink>
))}

谢谢!在你的例子中,我能把 views/index.js 拆分成一个单独的 npm 包吗?例如,它可以位于另一个 yarn 工作区或 npm link 包中吗? - mathan
@mathan 在另一个包中创建一个包含所需组件名称的数组。然后按如下方式导出该数组:module.exports = myArray。在 views/index.js 中导入该包并循环遍历导出的数组,将数组值插入循环输出中。这样就可以为您解决问题了。 - Andy Hoffman

0
为了补充@gor181的回答,我可以补充一下export必须是这样的: export { default as CompA } from "./comp_a"; export { default as CompB } from "./comp_b"; 希望这对你有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接