Unapedra
Unapedra

Reputation: 2373

How to retrieve a React component from an object property

I've got a SliderMenu React component, which receives an array containing its elements. These elements are objects, and one of their properties is the icon that will be shown in the menu:

function SliderMenu({ options }) {
  return (
    <>
      <Drawer open>
        <List>
          {options.map((item) => {
            const { icon: ItemIcon } = item || {};
            return (
              <ListItem button key={`menuItem_${item.text.replace(/\s/g, '')}`}>
                <ListItemIcon>
                  <ItemIcon />
                </ListItemIcon>
                <ListItemText primary={item.text} />
              </ListItem>
            );
          })}
        </List>
      </Drawer>
    </>
  );
}

This component is called from an upper component (because I'd like to be able to create multiple SliderMenu if I needed them), which specifies the elements array and passes them as props:

import React from 'react';
import { HomeRoundedIcon } from '@material-ui/icons/HomeRounded';
import SliderMenu from '../../components/SliderMenu';

function MainMenu() {
  const menuOptions = [
    {
      text: 'Home',
      icon: HomeRoundedIcon,
    },
  ];

  return (
    <SliderMenu options={menuOptions} />
  );
}

export default MainMenu;

The problem here is that whenever I try this code, ItemIcon is undefined, and I'm receiving the following error:

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.

Check the render method of SliderMenu.

However, if I try:

const menuOptions = [
    {
        text: 'Home',
        icon: <HomeRoundedIcon />,
    },
];

ItemIcon has a value, and I get the following error:

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

Check the render method of SliderMenu.

I would like to be able to specify different menu elements with different icons and so on, depending on the context, and then use the common component to render it and have a consistent behaviour across all menus.

How can I define the icon in the object, using the icon component library, and then pass it via props to the SliderMenu so it can render it (without having to import all the icons and make a switch to see which icon has to render)?

Upvotes: 0

Views: 5806

Answers (1)

Asaf Aviv
Asaf Aviv

Reputation: 11760

Change your import to a default import

import HomeRoundedIcon from '@material-ui/icons/HomeRounded'

or use a named import from @material-ui/icons path

import { HomeRounded as HomeRoundedIcon } from "@material-ui/icons"

You would also want to remove the default assignment and render the icon conditionally as this will throw an error when there is no icon

const { icon: ItemIcon } = item

{ItemIcon && (
  <ListItemIcon>
    <ItemIcon />
  </ListItemIcon>
)}

Upvotes: 3

Related Questions