The right way to use SVG icons with React
Tags: react, svg, import, webpack
Published: 2020-10-06 07:04:31

---
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/fa0exbeorhza092i2cof.jpg
title: The right way to use SVG icons with React
published: true
description: Elegant solution for creating SVG React Component based on dynamic import
tags: React, SVG, import, webpack
---

Hey, folks! I think you’ve read a lot of topics on how to use SVG in React.
The most popular approach is to use [@svgr/webpack](https://www.npmjs.com/package/@svgr/webpack) that allows you to import SVG as `ReactComponent`. If you create projects using awesome
[create-react-app](https://github.com/facebook/create-react-app) you already use this package.

Usually you do it this way, right?

```javascript
import React from 'react';
import { ReactComponent as Icon } from 'path/to/icon.svg';
function Icon() {
    return <Icon />;
}
```

It works perfectly, **BUT** what if you want to create **re-usable components** to render your icons.

*Let’s say, designer provides you a set of 50+ svg icons, how would you deal with them?*

Many tutorials suggest to create components for each icon — it is straightforward, but tiresome way. Not to mention it produces a lot of boilerplate code.😖

If you have curiosity how to avoid useless boilerplating — welcome to my post.

> *I’ll present you a **simple**, but **effective** way to manage SVG icons in your React App.*

---

## TL;DR

If you are too impatient to get the answer, it is okay.
**All you need to start using this elegant solution is a code snippet provided below.**

```javascript
import React, { useEffect, useState } from "react";

function Icon(props) {
  const { name, ...otherProps } = props;
	
  /* Use state hook to store icon module value */
  const [iconModule, setIconModule] = useState(null);

  useEffect(() => {
    /* Use dynamic import to get corresponding icon as a module */
    import(`./icons/${name}.svg`)
      .then((module) => {
        /* Persist data in state */
        setIconModule(module);
      })
      .catch((error) => {
        /* Do not forget to handle errors */
        console.error(`Icon with name: ${name} not found!`);
      });
  }, [ name /* update on name change */ ]);

  const renderIcon = () => {
    if (!iconModule) return null;

    /* Equal to: import { ReactComponent as Icon } from "./path/to/icon.svg" */
    const Component = iconModule.ReactComponent;

    return <Component {...otherProps} />;
  };

  return <>{renderIcon()}</>;
}
export default Icon;
```

Or you can play with it in [codesandbox.io/s/how-to-use-svg-icon-sets-in-react](https://codesandbox.io/s/how-to-use-svg-icon-sets-in-react-38q27?from-embed):

{% codesandbox how-to-use-svg-icon-sets-in-react-38q27 module=/src/Icon.js %}


---

## How it works

Let’s dive into this approach together and go through it line by line.
It is simpler than it looks.
First, we create a new *functional component* that takes one required `name` prop.

```javascript
function Icon({ name, ...otherProps }) {
    // implementation
}
```

Next, we use `useState` hook to store icon component value with `null` as initial value:

```javascript
const [iconModule, setIconModule] = useState(null);
```

That’s where the magic happens✨…
We use dynamic expression in `import` to get icon depending on provided `name`. `import` returns `Promise` which resolves with module on **success** or **rejects** Erorr if icon not found.

Here we work with webpack bundling.

`import(`./icons/${name}.svg`)` will cause every `.svg` file in the `./icons` directory to be bundled into the new chunk. At run time, when the variable name has been computed, any file like `star.svg` will be available for consumption. You can read more about this [here](https://webpack.js.org/api/module-methods/#dynamic-expressions-in-import).


```javascript
import(`./icons/${name}.svg`).then((module) => {
    /* Persist data in state */
    setIconModule(module);
}).catch((error) => {
    /* Do not forget to handle errors */
    console.error(`Icon with name: ${name} not found!`);
});
```


Finally, we should render our icon component if it is successfully imported. Webpack applies [@svgr/webpack](https://www.npmjs.com/package/@svgr/webpack) loader
on dynamic import: `import(`./icons/${name}.svg`)`
same way it does for
static one: `import Icon from “./path/to/icon.svg”`

```javascript
const renderIcon = () => {
    if (!iconModule) return null;
    /**
    * Equal to:
    * import { ReactComponent as Icon } from "./path/to/icon.svg";
    */
    const Component = iconModule.ReactComponent;
    return <Component {...otherProps} />;
};
```

That’s it guys 🎉.
Hope you enjoyed article and going to apply new knowledge for your next app. Feel free to comment and discuss it!

{% medium https://medium.com/@barr.develop/the-right-way-to-use-svg-icons-with-react-e1bcab58d65a %}