Dynamic import and component rendering by string name

Viewed 393

I have a data set for some simple actions. Each action has a corresponding color and Material-UI icon. There are about 1,100 available icons. The data looks like this:

{ "items":
[{ "action": "Run",
        "icon": "DirectionsRunIcon",
        "color":"Red"},
{ "action": "Jump",
        "icon": "ArrowUpwardIcon",
        "color":"Blue"},
{ "action": "Walk",
        "icon": "DirectionsWalkIcon",
        "color":"Green"},
]}

Each of the icons requires importing a separate library like so:

import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward'

I could be using any number of icons from @material-ui/icons/ and they're obviously stored as a string in the data. So the question is, how can I conditionally render the icons and only load what I need?

Currently I have a function that just does a huge switch, which won't work long term.

function getIcon(action) {
  switch (action) {
    case "Run":
      return <DirectionsRunIcon />;
    case "Jump":
      return <ArrowUpwardIcon />;
...

Thanks!

2 Answers

Since you have already have the reference name of the Icon in your datset, you may use the function below:

import { find } from 'lodash';

const getIcon = (action) => {
  const requiredObj = find(items, { action }) || {};
  return requiredObj.icon;
};

Now, you can use the resulting name to do a dynamic import.

Using something like @loadable/component, you could try to load dynamicly the icon with

import loadable from '@loadable/component';

const Icon = ({name, ...rest}) => {
  const ImportedIcon = loadable(() =>
    import(`@material-ui/icons/${name}`),
  );

  return <ImportedIcon {...rest} />;
};
Related