如何使用标记动态创建组件?

时间:2018-04-12 12:04:23

标签: javascript reactjs jsx

我想为导入的组件动态创建JSX标记。所以我的想法是这样的:

import DemoComponent from './DemoComponent';

class DynamicRendering extends Component {

  assembleResult() {
    const {
      democomponent
    } = this.props;

    const result = [];

    if (democomponent) {
      const Tag = `DemoComponent`;
      result.push(<Tag />);
    }

    return result;
  }

  render() {
    const result = this.assembleResult();
    return result;
  }
}

我的想法是,我可以将几个不同的道具传递给组件,然后组件动态创建JSX标签并将它们组合在一起。我想要这个的原因是因为我想要动态渲染大约15个组件。而不是隐式地写它们我宁愿在它们上面做一个循环,并在需要时动态创建它们。这样我可以保持这个组件DRY。

上面代码的问题在于,如果您创建这样的标记,它将把它作为HTML元素。这会导致错误,因为没有像'DemoComponent'这样的HTML元素。我设法通过创建道具名称到应该加载的组件的映射来解决这个问题。见下面的例子:

import DemoComponent from './DemoComponent';

const PROP_MODULE_MAP = new Map([
  ['democomponent', DemoComponent]
]);

class DynamicRendering extends Component {

  assembleResult() {
    const {
      democomponent
    } = this.props;

    const result = [];

    if (democomponent) {
      const Tag = PROP_MODULE_MAP.get('democomponent');
      result.push(<Tag />);
    }

    return result;
  }

  render() {
    const result = this.assembleResult();
    return result;
  }
}

但我想知道是否有更简单的方法然后创建这个地图。还有另一种方法可以动态创建代表导入组件的JSX标记吗?

2 个答案:

答案 0 :(得分:1)

您可以让父母传递所需的组件类型:

<强> Parent.js

import SomeComponent from './someComponent';
import Child from './child';

// the parent renders Child and passes the type SomeComponent as a prop
const Parent = () => <Child Elem={SomeComponent} />

<强> Child.js

// the Child renders the component type passed
// note that the prop "Elem" is capitalized so that it will not be treated as a html node
const Child = ({Elem}) => <Elem />;

export default Child;

这样Child组件就能够呈现它传递的任何组件类型。这样更灵活,并且不需要Child知道它应该在编译时呈现的所有组件。

请注意,在子项中呈现传递的组件类型时,要呈现的变量必须大写,否则它将被视为通常的html节点。有关详细信息,请参阅User-Defined Components Must Be Capitalized

如果您不希望将prop名称大写,则可以在呈现它之前将值重新分配给子项中的大写名称:

const Child = ({elem: Elem}) => <Elem />;    

答案 1 :(得分:0)

我不知道你的项目布局是什么,但我建议你可以做这样的事情:
components文件夹中为动态组件导入创建一个文件:

import Comp1 from './Comp1'
import Comp2 from './Comp2'

export default { Comp1, Comp2 }

为动态渲染的函数创建一个帮助器:

import components from './components/dynamic'

const renderComponents = compNames => {
    // take compNames as a list
    const compsToRender = compNames.map(name => components[name])
    // get all components by compNames provided and return them in array
    return compsToRender.map(Component => <Component />)
}

然后在你想要的地方打电话。

<App>
    {renderComponents(['Comp1', 'Comp2'])}
</App>

如果你想传递带有组件名称的道具,你可以传递对象而不是字符串并将它们传递给函数内的组件,但我不明白为什么它会更好然后只使用带有props的普通组件