Search code examples
reactjsreact-icons

React - Generating different Icons within a map function


I have a sidebar components whose list items are generated inside of a map function (movie genres fetched from an api). I would like to have a different icon next to each of the movie genres but have been unable to figure out a way to create a different for each run of the map function.

My thoughts are 1st: make an array of the icons I would like to display, in the order that I would like them to display in.

 const icons = [
    "AiOutlineHome ",
    "FaUserNinja",
    "GiSwordman",
    "GiBabyFace",
    "FaLaughBeam",
    "GiPistolGun",
    "GiPineTree",
    "GiDramaMasks",
    "GiFamilyHouse",
    "GiElfEar",
    "GiScrollUnfurled",
    "GiScreaming",
    "GiMusicalNotes",
    "GiMagnifyingGlass",
    "FaRegKissBeam",
    "GiMaterialsScience",
    "GiHalfDead",
    "GiGreatWarTank",
    "GiCowboyBoot",
  ];

Then in my map function generate a different icon for each list item

{movieGenres.map((genre) => {
            return (
              <li key={genre.id} className="nav-text">
                <button
                  className="genre-btn"
                  onClick={() => genreSelectionHandler(genre.id)}
                >
                  *<GENERATE ICON HERE />*
                  <span className="nav-item-title">{genre.name}</span>
                </button>
              </li>
            );
          })}

Is it possible to pragmatically create components like this? So that I can avoid creating each list item individually if I want different icon.


Solution

  • You can just take the index of your genre to get the icon. The index is the second argument to the callback of your map() function:

    {movieGenres.map((genre, idx) => (
        <li key={genre.id} className="nav-text">
            <button
                className="genre-btn"
                onClick={() => genreSelectionHandler(genre.id)}
            >
                <Icon icon={icons[idx]} />
                <span className="nav-item-title">{genre.name}</span>
            </button>
        </li>
    ))}
    

    The Icon component would render the icon depending on what kind of icons you are using.

    EDIT:

    As you want to use react-icons you need to import the actual icon components rather than just using strings:

    import {AiOutlineHome} from "react-icons/ai";
    import {FaUserNinja} from "react-icons/fa";
    // ....
    
    const icons = [
        AiOutlineHome,
        FaUserNinja,
        // ...
    ];
    

    And render them:

    {movieGenres.map((genre, idx) => {
        // must be a capitalized name in order for react to treat it as a component
        const Icon = icons[idx];
    
        return (
            <li key={genre.id} className="nav-text">
                <button
                    className="genre-btn"
                    onClick={() => genreSelectionHandler(genre.id)}
                >
                    <Icon />
                    <span className="nav-item-title">{genre.name}</span>
                </button>
            </li>
        )
    })}