简体   繁体   English

在React中动态创建组件

[英]Dynamically create components in React

I am using react-icons and I have a JSON file as follows: 我正在使用react-icons,并且有一个JSON文件,如下所示:

social: {
  twitter: {
    icon: 'FaTwitter',
    link: 'twitterlink',
  },
  linkedin: {
    icon: 'FaLinkedIn',
    link: 'linkedinlink',
  },
  github: {
    icon: 'FaGithub',
    link: 'githublink',
  },
}

I am trying to dynamically create the icons by looping through the JSON, but I'm having a lot of trouble making it work. 我正在尝试通过遍历JSON来动态创建图标,但在使其正常工作时遇到了很多麻烦。

Here are snippets of what I've already tried so far along with the outputs and the errors produced in the console: 以下是到目前为止我已经尝试过的内容以及控制台中产生的输出和错误的摘要:


React Icons import 反应图标导入

import * as FontAwesome from 'react-icons/lib/fa';

1 1

{Object.keys(social).map(key => {
  let IconName = Component['FontAwesome.' + social[key].icon];

  return (
    <li key={key}>
      <a href={social[key].link} target="_blank" rel="noopener">
        <IconName size="15" />
      </a>
    </li>
  );
})}

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. 警告:React.createElement:类型无效-预期为字符串(对于内置组件)或类/函数(对于复合组件),但得到:未定义。 You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. 您可能忘记了从定义文件中导出组件,或者可能混淆了默认导入和命名导入。

Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. 未捕获的错误:元素类型无效:预期为字符串(对于内置组件)或类/函数(对于复合组件),但得到:未定义。 You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. 您可能忘记了从定义文件中导出组件,或者可能混淆了默认导入和命名导入。

No output 无输出


2 2

{Object.keys(social).map(key => {
  let IconName = FontAwesome`.${social[key].icon}`;

  return (
    <li key={key}>
      <a href={social[key].link} target="_blank" rel="noopener">
        <IconName size="15" />
        {/* This line produces the same result */}
        {/* {React.createElement(IconName, { size: '15' })} */}
      </a>
    </li>
  );
})}

Uncaught TypeError: __WEBPACK_IMPORTED_MODULE_1_react_icons_lib_fa__ is not a function 未捕获的TypeError: __WEBPACK_IMPORTED_MODULE_1_react_icons_lib_fa__不是函数

No output 无输出


3 3

{Object.keys(social).map(key => {
  let IconName = `FontAwesome.${social[key].icon}`;

  return (
    <li key={key}>
      <a href={social[key].link} target="_blank" rel="noopener">
        <IconName size="15" />
      </a>
    </li>
  );
})}

Warning: <FontAwesome.FaTwitter /> is using uppercase HTML. 警告: <FontAwesome.FaTwitter />正在使用大写HTML。 Always use lowercase HTML tags in React. 在React中始终使用小写的HTML标签。

Warning: The tag <FontAwesome.FaTwitter> is unrecognized in this browser. 警告:此浏览器无法识别标签<FontAwesome.FaTwitter> If you meant to render a React component, start its name with an uppercase letter. 如果要渲染React组件,请以大写字母开头。

There are more errors but for FaLinkedIn and FaGithub which are the same. 除了FaLinkedInFaGithub ,还有更多错误。

Output in react dev tool 在React开发工具中输出

<li>
  <a href="twitterlink" target="_blank" rel="noopener">
    <Fontawesome.FaTwitter size="15"></Fontawesome.FaTwitter>
  </a>
</li>

HTML output HTML输出

<li>
  <a href="twitterlink" target="_blank" rel="noopener">
    <fontawesome.fatwitter size="15"></fontawesome.fatwitter>
  </a>
</li>

What I want is something like this: 我想要的是这样的:

<FontAwesome.FaTwitter size="15" />

Output in react dev tool 在React开发工具中输出

<FaTwitter size="15">
  <IconBase viewBox="0 0 40 40" size="15">
    <svg fill="currentColor" preserveAspectRatio="xMidYMid meet" height="15" width="15" viewBox="0 0 40 40" style="vertical-align: middle;">
      <g>
        <path d="m37.7 9.1q-1.5 2.2-3.7 3.7 0.1 0.3 0.1 1 0 2.9-0.9 5.8t-2.6 5.5-4.1 4.7-5.7 3.3-7.2 1.2q-6.1 0-11.1-3.3 0.8 0.1 1.7 0.1 5 0 9-3-2.4-0.1-4.2-1.5t-2.6-3.5q0.8 0.1 1.4 0.1 1 0 1.9-0.3-2.5-0.5-4.1-2.5t-1.7-4.6v0q1.5 0.8 3.3 0.9-1.5-1-2.4-2.6t-0.8-3.4q0-2 0.9-3.7 2.7 3.4 6.6 5.4t8.3 2.2q-0.2-0.9-0.2-1.7 0-3 2.1-5.1t5.1-2.1q3.2 0 5.3 2.3 2.4-0.5 4.6-1.7-0.8 2.5-3.2 3.9 2.1-0.2 4.2-1.1z">
        </path>
      </g>
    </svg>
  </IconBase>
</FaTwitter>

HTML Output HTML输出

<svg fill="currentColor" preserveAspectRatio="xMidYMid meet" height="15" width="15" viewBox="0 0 40 40" style="vertical-align: middle;">
  <g>
    <path d="m37.7 9.1q-1.5 2.2-3.7 3.7 0.1 0.3 0.1 1 0 2.9-0.9 5.8t-2.6 5.5-4.1 4.7-5.7 3.3-7.2 1.2q-6.1 0-11.1-3.3 0.8 0.1 1.7 0.1 5 0 9-3-2.4-0.1-4.2-1.5t-2.6-3.5q0.8 0.1 1.4 0.1 1 0 1.9-0.3-2.5-0.5-4.1-2.5t-1.7-4.6v0q1.5 0.8 3.3 0.9-1.5-1-2.4-2.6t-0.8-3.4q0-2 0.9-3.7 2.7 3.4 6.6 5.4t8.3 2.2q-0.2-0.9-0.2-1.7 0-3 2.1-5.1t5.1-2.1q3.2 0 5.3 2.3 2.4-0.5 4.6-1.7-0.8 2.5-3.2 3.9 2.1-0.2 4.2-1.1z">
    </path>
  </g>
</svg>

Is what I'm trying to do possible? 我想做的事可能吗? Are there any workarounds or another way of doing it? 有任何解决方法或其他方法吗?

There are similar questions are StackOverflow but none seems to be working for me, that's why I asking a new one. 有类似的问题是StackOverflow,但似乎没有一个对我有用,这就是为什么我要一个新的问题。 I've also tried googling the errors but no luck there either. 我也尝试过搜索错误,但也没有运气。

Here is how to create react-icons dynamically given the name of the icon: 在给定react-icons名称的情况下,以下是动态创建react-icons的方法:

import React from "react";
import { render } from "react-dom";
import * as FontAwesome from "react-icons/lib/fa";

const Icon = props => {
  const { iconName, size, color } = props;
  const icon = React.createElement(FontAwesome[iconName]);
  return (
    <div style={{ fontSize: size, color: color }}>{icon}</div>
  );
};

Once you have this icon wrapper, just use it as a normal React component: 一旦有了这个图标包装器,就可以将其用作常规的React组件:
<Icon iconName={"FaBeer"} size={12} color="orange" />
The icon name should follows MixedCaps naming conversion. 图标名称应遵循MixedCaps命名转换。

This link is a codesandbox demo of the code above: https://codesandbox.io/s/o715x22m4z 此链接是上面代码的codesandbox演示: https ://codesandbox.io/s/o715x22m4z

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM