Dawid Banachowski
Dawid Banachowski

Reputation: 59

How to import and render svg file based on given name from variable in React?

Problem

I have a large array of categories and a variable whose value is one of the categories, lets say

const categories = ['a1', 'a2', ..., 'a200'];
const category = 'a57';

I have a svg file corresponding to each category name: 'a1.svg', 'a2.svg', ..., 'a200.svg'

My problem is that, I need to render only one svg file, based on a variable that comes from categories array and I can't render it as image, because I need to be able to change it's fill/stroke value.

<img src={`./images/${category}.svg} />

I tried to import all the svgs like this

import {ReactComponent as a1} from './images/ai.svg';

and put all those imports in array. But when I did it this way, I had an array of objects like this. In theory I could work with that, but some of my categories had spaces and other symbols and I couldn't use .render.name value since you can't import like this {ReactComponent as martial arts}. It's also uncomfortable cause I need to do a lot of imports instead of doing something like

const images = categories.map(category => {
  return {
    name: category,
    svg: require(`./images/${category}.svg`
  }
})

I also tried to make an array of objects which would look like this

const images = [ {name: 'a1', svg: a1}, {name: 'a2', svg: a2} ];

and render it as

{images.find(img => img.name === category).svg}

but I couldn't cause it would give me this error

Error: Objects are not valid as a React child (found: object with keys {$$typeof, render}). If you meant to render a collection of children, use an array instead.

Goal

Render only one svg component based on the category variable that's value could be anything from the categories array. Also, how to correctly import those svgs in a way that would allow me to easily render the svg and change its fill/stroke value in CSS.

Something similiar to making an import like this to work

import {ReactComponent as imageCategory} from `./images/${category}.svg`

Upvotes: 3

Views: 2342

Answers (1)

lissettdm
lissettdm

Reputation: 13078

The error:

Error: Objects are not valid as a React child (found: object with keys {$$typeof, render}). If you meant to render a collection of children, use an array instead.

This occurs because you are not rendering the component, you are just getting the component instance:

const Svg = images.find(img => img.name === category).svg //--> component instance

return <Svg /> //--> render it

//--> **Note:** this just an example it won't work because it won't find the module.

To make it work

If you are using Webpack, you can use require.context:

const svgDir = require.context("!@svgr/webpack!./images");

const images = categories.map(category => {
  return {
    name: category,
    svg: svgDir(`./${category}.svg`).default
  }
});

then:

 const renderImgByCategory = (category) => {
     const Svg = images.find(img => img.name === category).svg;
     return <Svg/>
 }

JSX:

{renderImgByCategory(category)}

Upvotes: 2

Related Questions