【问题标题】:How to dynamically create components with Tags?如何动态创建带有标签的组件?
【发布时间】:2018-04-12 12:04:23
【问题描述】:

我想为导入的组件动态创建 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;
  }
}

我的想法是我可以将几个不同的 props 传递给组件,然后组件动态地创建 JSX 标签并将它们组装在一起。我想要这个的原因是我有大约 15 个要动态渲染的组件。我宁愿对它们进行循环并在需要时动态创建它们,而不是隐式地编写它们。这样我就可以保持这个组件干燥。

上面代码的问题是,如果你像这样创建一个Tag,它将把它当作一个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 标签吗?

【问题讨论】:

标签: javascript reactjs jsx


【解决方案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

如果您不希望道具名称大写,您可以在渲染之前将值重新分配给孩子中的大写名称:

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

【讨论】:

    【解决方案2】:

    我不知道你的项目布局是什么,但我建议你可以这样做:
    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,你可以传递对象而不是字符串,然后在函数内部的组件中传递它们,但我不明白为什么使用带有 props 的普通组件会更好

    【讨论】:

      猜你喜欢
      • 2019-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-23
      • 1970-01-01
      • 2013-04-15
      相关资源
      最近更新 更多