I've been doing iteration map with react for quite long now with many success. The only thing I haven't encounter is rendering SVG with iteration.
Start with react ponent setting up iteration mp and importing array of data from ./data.js
.
Cards.js
import React from 'react';
import data from './data';
const icons = data.map(icon => (
<>
<div><span>{icon.svg}</span> {icon.type}</div>
</>
));
const Cards = () => (<>{ icons }</>);
export default Cards;
Array of data...
data.js
export default[
{
svg: './icons/menu.svg',
type: Menu
},
{
svg: './icons/home.svg',
type: Home
},
{
svg: './icons/clock.svg',
type: History
}
]
Problem is, its unable to render .svg following directory but end up rending string ./icons/xxx.svg
instead.
I've tried another method..
svg: require('./icons/clock.svg'),
... still getting same result. I'm Running out of idea. Any suggestions? I understand require('')
worked with JSX img tag... But I wanetd .svg files only, is there a way to import svg files into data array?
I've been doing iteration map with react for quite long now with many success. The only thing I haven't encounter is rendering SVG with iteration.
Start with react ponent setting up iteration mp and importing array of data from ./data.js
.
Cards.js
import React from 'react';
import data from './data';
const icons = data.map(icon => (
<>
<div><span>{icon.svg}</span> {icon.type}</div>
</>
));
const Cards = () => (<>{ icons }</>);
export default Cards;
Array of data...
data.js
export default[
{
svg: './icons/menu.svg',
type: Menu
},
{
svg: './icons/home.svg',
type: Home
},
{
svg: './icons/clock.svg',
type: History
}
]
Problem is, its unable to render .svg following directory but end up rending string ./icons/xxx.svg
instead.
I've tried another method..
svg: require('./icons/clock.svg'),
... still getting same result. I'm Running out of idea. Any suggestions? I understand require('')
worked with JSX img tag... But I wanetd .svg files only, is there a way to import svg files into data array?
- 1 Have you tried this <div><span>{require(icon.svg)}</span> {icon.type}</div> – Hemadri Dasari Commented Oct 12, 2018 at 17:52
4 Answers
Reset to default 4Try setting it up like so:
import menu from './icons/menu.svg';
import home from './icons/home.svg';
import clock from './icons/clock.svg';
export default[
{
svg: menu,
type: 'Menu'
},
{
svg: home,
type: 'Home'
},
{
svg: clock,
type: 'History'
}
]
And implement it like this:
<div>
<span>
<img src={icon.svg} />
</span>
{icon.type}
</div>
Thank you guys taking time to help... Those method do work, gave me idea and I am keeping note of it. But it was not exactly what I was looking for since it'd have to use <img>
tags which will not allow me to adjust size, color or etc. I want to avoid going back and forth between code editor and illustration programs. Fortunately, I found alternative solution, it may be tedious but it works. Here what I did...
Start with creating React PropTypes ponent..
Icon.js
import React from 'react';
import PropTypes from 'prop-types';
const config = {
svg: {
display: 'flex-inline',
margin: '0 auto'
}
};
const Icons = props => (
<svg
style={config.svg}
width={`${props.size}`}
height={`${props.size}`}
viewBox={`0 0 512 512`}
className={props.className}
>
<path d={props.icon} />
</svg>
);
Icons.propTypes = {
icon: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
color: PropTypes.string,
className: PropTypes.string.isRequired
};
Icons.defaultProps = {
size: 32
};
Create another file and include array of SVG path with defined name eg. menu, home, clock
icons.js
export const SVGicon = {
menu: /*Insert your SVG path here starting with 'M...*/,
home: /*Insert your SVG path here starting with 'M...*/,
clock: /*Insert your SVG path here starting with 'M...*/,
}
Back to data.js and modify a little (Thank you Ted!)
data.js
import { SVGicon } from './icons'
export default[
{
svg: SVGicon.menu,
type: 'Henu'
},
{
svg: SVGicon.home,
type: 'Home'
},
{
svg: SVGicon.clock,
type: 'History'
}
]
Back to react ponents and modify a little...
Cards.js
import React from 'react';
import data from './data';
import Icon from './Icon'; /* PropType Component */
const icons = data.map(icon => (
<React.Fragment>
<Icons icon={icon.svg} className="svg-icon" size={12} />
</React.Fragment>
));
const Cards = () => (<React.Fragment>{ icons }</React.Fragment>);
export default Cards;
and the css following className="svg-icon"
to adjust color, effect and etc
main.scss
.svg-icon{
fill: rgba(blue, .5);
transition: fill .3s ease-out;
&:hover{
fill: rgba(red, 1);
}
This should show array of different SVG icons, with ability to control color, size and etc... Hope this help
Keep your data as it is and use require to render it
<div>
<span>
{require(icon.svg)}
</span>
{icon.type}
</div>
I would have added this as a ment to @sirrius, but not enough reputations :)
I followed the solution provided but my icons were not visible. This is because the view port is still taking static values, instead of the dynamic size values for width and height.
So instead of:
const Icons = props => (
<svg
style={config.svg}
width={`${props.size}`}
height={`${props.size}`}
viewBox={`0 0 512 512`}
className={props.className}
>
<path d={props.icon} />
</svg>
);
which would have the icons taking a viewBox height and width of 512 irrespective of the size prop (imagine having an svg of size 32 inside a 512 viewBox, it could appear to be out of sight cause of the dimensions are not proportional).
You should have:
const Icons = props => (
<svg
style={config.svg}
width={`${props.size}`}
height={`${props.size}`}
viewBox={`0 0 ${props.size} ${props.size}`}
className={props.className}
>
<path d={props.icon} />
</svg>
);
This adjusts the viewBox with respect to the size provided.