4

I'm using React-icons in my ReactJS project and I just wanted to loop (by Map method) the specific icons in each JSX field when data is render.

In other word, I want this{`<${e.contact.icons}/>`}in JSX code. Here is my code section:-

Here is, I import some icons for React icons.

import { FaBeer, Fa500Px, FeAccusoft } from "react-icons/fa";

Here is a data array which I want to render in JSX.

const data = [
  {
    contact: [
      {
        title: 'contact',
        icons: 'FaBeer',
      },
      {
        title: 'contact',
        icons: 'Fa500Px',
      },
      {
        title: 'contact',
        icons: 'FaAccusoft',
      },
    ],
  },
]

And this is my component in down below. Which I'm using icons. You get little idea what I want to do.

const contact = () => {
  return (
    <>
      {data.map((e, i) => {
        return (
          <>
            <div className="text-area">
              <span> {`<${e.contact.icons}/>`} </span>
            </div>
          </>
        );
      })}
    </>
  );
};

export default contact;

I'm trying to use like this{`<${e.contact.icons}/>`}, but is not working. When I see in browser. It's look like this.

<FaBeer/>
<Fa500Px/>
<FaAccusoft/>

It's just return like a text, but I want to get icons.

Any suggestion ?

7 Answers 7

6

https://codesandbox.io/s/fervent-goldwasser-y83cn?file=/src/App.js

import { FaBeer, Fa500Px, FaAccusoft } from "react-icons/fa";

// here is data for I want to show

const data = [
  {
    contact: [
      {
        title: "contact",
        subtitle: "get in touch",
        icons: FaBeer
      },
      {
        title: "contact",
        subtitle: "get in touch",
        icons: Fa500Px
      },
      {
        title: "contact",
        subtitle: "get in touch",
        icons: FaAccusoft
      }
    ]
  }
];

const contact = () => {
  return (
    <>
      {data.map((e, i) => {
        return (
          <>
            {e.contact.map((e, i) => {
              return (
                <div className="text-area" key={i}>
                  <h1 className="title">{e.title}</h1>
                  <h2 className="subtitle">{e.subtitle}</h2>
                  <span>
                    <e.icons />
                  </span>
                </div>
              );
            })}
          </>
        );
      })}
    </>
  );
};

export default contact;

Sign up to request clarification or add additional context in comments.

1 Comment

I'm honestly surprised that <e.icons/> works as I thought that a capitalized name was a strict requirement. Possibly it's ok because the actual value of e.icons is a component with a capitalized name?
3

You cannot use strings to represent React Component Types, instead you can use the imported ComponentType itself.

import { FaBeer, Fa500Px, FaAccusoft } from "react-icons/fa";

// here is data for I want to show

const data = [
  {
    contact: [
      {
        title: "contact",
        subtitle: "get in touch",
        icons: FaBeer,
      },
      {
        title: "contact",
        subtitle: "get in touch",
        icons: Fa500Px,
      },
      {
        title: "contact",
        subtitle: "get in touch",
        icons: FaAccusoft,
      },
    ],
  },
];

const Contact = () => {
  return (
    <>
      {data.map((e, i) => {
        const Icon = e.contact.icons;
        return (
          <>
            <div className="text-area">
              <h1 className="title">{e.contact.title}</h1>
              <h2 className="subtitle">{e.contact.subtitle}</h2>
              <span><Icon /></span>
            </div>
          </>
        );
      })}
    </>
  );
};

export default Contact;

Note how the rendering of the icon changes as well. I have assigned the icon component to a variable Icon instead of calling <e.contact.icons/> directly because React expects components to start with a capital letter.

The Icon variable will be a React component (either a function component or a class component) so you can call that component by using standard JSX <Icon /> syntax. You can also pass any of the react-icons props, for example: <Icon color="#FF0000" size={24}/>.

2 Comments

@SanskarSahu Not sure what you mean
This is a good answer. I edited it to provide a bit more information.
2
+100

Well, the option of importing FaIcon-s and putting them into "data" array looks pretty nice:

import { FaBeer, Fa500Px, FaAccusoft } from "react-icons/fa";

const data = [
  {
    contact: [
      {
        title: "contact",
        subtitle: "get in touch",
        icons: FaBeer,
      },
...

On the other hand possibility of generating components "dynamically" by their string name could be still implemented.

Firstly, I find usefull following article: React / JSX Dynamic Component Name

Next, I've created a new FaIconDynamic component:

import {
    AiFillAccountBook,
    AiFillAlert,
    AiFillAlipayCircle,
    AiFillAndroid,
} from 'react-icons/ai';

export const FaIconDynamic = ({ type }) => {
    const FaIcon = components[type];
    return <FaIcon></FaIcon>;
};

const components = {
    AiFillAccountBook,
    AiFillAlert,
    AiFillAlipayCircle,
    AiFillAndroid,
};

And then that's pretty easy to generate any registered above fa-icon, f.e.:

function App() {
    return (
        <>
            <FaIconDynamic type={'AiFillAccountBook'} />
            <FaIconDynamic type={'AiFillAlert'} />
            <FaIconDynamic type={'AiFillAlipayCircle'} />
            <FaIconDynamic type={'AiFillAndroid'} />
        </>
    );
}

Of course, both approaches have their pros and cons and could be more benefitial in some situations over each other

1 Comment

Your help is appreciable @Uladzimir. It looked like you did pretty well search on it.
1

I have got the answer. I know the answer is not an ideal one, but it's work for me just now. The problem with the answer is that. We imported all the fonts from react-icons. So, I guess, as we will grow the project larger. It will decrease the performances and the major factor of could be react icons. And also as Mr.Ali Shefaee describe in the comment section.

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

Now that section we could use two type of method.

First one :-

Here we import the all icons and use the function to get specific icon which we want

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

render(<App />, document.getElementById("root"));

And Second :-

  const App = () => {
  const iconString = "FaBeer";
  const beer = React.createElement(FontAwesome[iconString]);
  return (
    <div>
      <FontAwesome.FaBeer />
      <div style={{ fontSize: 24, color: "orange" }}>{beer}</div>
    </div>
  );
};


render(<App />, document.getElementById("root"));

Here is the Demo:- Codesandbox.

Thank to怈Evie.Codes怉.

1 Comment

but this way do you think it is good for memory to import the whole FontAwesome package into this function scope? or it is better to import just required icons.
1

It seems that the current answers already addresses the problem, so this only attempts to add small improvement for the solution. Here is an approach I tried in a similar situation.

Simplified demo on: stackblitz

This will keep data the same as posted in the question as it might need to be fetched:

const data = [
  {
    contact: [
      {
        title: 'contact',
        icons: 'FaBeer',
      },
      {
        title: 'contact',
        icons: 'Fa500Px',
      },
      {
        title: 'contact',
        icons: 'FaChrome',
      },
    ],
  },
];

Define an object with the imported icons as static data:

import { FaBeer, Fa500Px, FaChrome } from 'react-icons/fa';
const icons = { FaBeer, Fa500Px, FaChrome };

In the output, the icon can taken out from static data, and rendered on condition:

const Contact = () => {
  return (
    <>
      {data.map((e, i) => (
        <React.Fragment key={i}>
          {e.contact.map((item, index) => {
            const Icon = icons?.[item.icons];
            return (
              <div key={index} className="text-area">
                <span>{Icon && <Icon size="3em" color="hotpink" />}</span>
              </div>
            );
          })}
        </React.Fragment>
      ))}
    </>
  );
};

export default contact;

1 Comment

Thank you for your feedback, [email protected] Li. But, it is a little modification. It not resolves the current issue. In your answer. We need to traverse the entire icons?.[item.icons]; it's depending up on the icons. As you know, icons is the object which is the collection of few elements { FaBeer, Fa500Px, FaChrome };. If I change in my data object and add some more icons or remove some icons. It will cause some error. The only option as I can see is to import all the icons from react-icons/fa but. It will decrease the performance when project grows large and not good for memory.
1

import { FaBeer, Fa500Px, FeAccusoft } from "react-icons/fa";

note: there is a typo in the name of the icon you imported .. it should be FaAccusoft

my suggestion for your question is to store the Icon components themselves in the object property .. so instead of storing it as string: "FaBeer" ... store it as a component: <FaBeer /> directly inside the object property .. like this:

const data = [
  {
    contact: [
      {
        title: "contact-1",
        icons: <FaBeer />
      },
      {
        title: "contact-2",
        icons: <Fa500Px />
      },
      {
        title: "contact-3",
        icons: <FaAccusoft />
      }
    ]
  }
];

and then you can simply loop over them

const Contact = () => {
  return (
    <>
      {data.map((e, i) => {
        return (
          <>
            {e.contact.map((c) => {
              return (
                <div className="text-area">
                  {c.title}
                  <span>
                    {c.icons} // you simply call it like this and the icon will be rendered
                  </span> 
                </div>
              );
            })}
          </>
        );
      })}
    </>
  );
};

1 Comment

Your help is appreciable @Raafat dev. But, the things are, I have no plan to make data static. It will be dynamic. I fetch from server, So, As you guess. Your answer is very obvious. I already try that but, it’s my helplessness to convert data into string. My question is only an example. As you know, the data is in array in object or JSON form. So, the most of the case, i not able to render elements as components.
0

You can also use Parser() from html-react-parser. https://github.com/remarkablemark/html-react-parser

const parse = require('html-react-parser');
{parse(`<${e.contact.icons}/>`)};

3 Comments

did you add - import { FaBeer, Fa500Px, FaAccusoft } from "react-icons/fa"; in your file
yes, let me create codesandbox.io for you, give some time
the npm package has an issue with capital case elements, { FaBeer, Fa500Px, FaAccusoft } github.com/remarkablemark/html-react-parser/issues/62 I can see in the browser the elements are parsed and rendered with lowercase like fabeer,fa500px,faaccusoft and browser does not recognize them. the lib says to add { htmlparser2: { lowerCaseTags: false } } option, but still it doesnot work according to git issue. ill see if there is any other lib or fix for this

Your Answer

By clicking ā€œPost Your Answerā€, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.