SVGR works beautifully with a single static SVG file with Parcel
https://www.smooth-code.com/open-source/svgr/docs/parcel/
However, when I try to load SVG dynamically according to user's interaction I face some difficulites.
I also checked the doc of Parcel https://parceljs.org/code_splitting.html, so I mimicked the syntax and did something like this in a class component:
const floors = {
'111': import('./assets/svg/floor_plan.svg'),
'222': import('./assets/svg/floor_plan_2.svg')
};
renderFloor = async (name) => {
const Floor = await floors[name];
console.log(Floor);
return <Floor />;
};
render() {
return <React.Fragment>{this.renderFloor('222')}</React.Fragment>;
}
console.log(Floor); returns something like this
{default: ƒ, __esModule: true}
default: ƒ SvgFloorPlan2(props)
__esModule: true
__proto__: Object
If I just do a easyimport Floor from './assets/svg/floor_plan_2.svg' like the doc andconsole.log(Floor), I got this
ƒ SvgFloorPlan2(props) {
return _react.default.createElement("svg", _extends({
className: "floor_plan_2_svg__floor_plan",
viewBox: "-1944.66 -1944.66 159462 126395"
}, props), _ref, _ref2);…
I wonder how to dynamically load SVG at run-time, thank you very much!
Hello @chloesun, with dynamic import, you have to specify that you want the default export.
const floors = {
'111': import('./assets/svg/floor_plan.svg'),
'222': import('./assets/svg/floor_plan_2.svg')
};
renderFloor = async (name) => {
const Floor = (await floors[name]).default; // the fix
console.log(Floor);
return <Floor />;
};
render() {
return <React.Fragment>{this.renderFloor('222')}</React.Fragment>;
}
I am wondering if dynamic imports really work with the @svgr/webpack setup. I tried it and it says You may need an appropriate loader to handle this file type. After searching about it, I found this issue where it should work and this other issue where it doesn't work.
My code:
const Item = ({ iconString }) => {
const Icon = import(`../../icons/${iconString}.svg`).then(
module => module.default,
);
return (
<div>
<Icon height="60px" width="60px" />
</div>
);
};
Can I get this to work with dynamic imports or is it not yet supported? :)
If this can be done with dynamic imports, I think I need to import it somehow with { ReactComponent } though, but not sure how it would work then. Maybe someone can help here ❤️
@rwieruch
Sorry to bother, but any chance you have figured out to dynamic import SVG in CRA with { ReactComponent } in mind? 😌
@adriandmitroca Unfortunately not. TBH I didn't pursue this any further after I didn't get to any solution.
@rwieruch
I figured out a reasonable solution, which is basically using normal dynamic import that resolves to SVG url and then use react-inlinesvg afterwards, like this:
import SVG from 'react-inlinesvg';
useEffect(() => {
async function loadIcon() {
if (icon) {
setIconComponent(<SVG src={(await icon).default} />);
}
}
loadIcon();
}, [icon]);
Doing like this.
import * as React from "react";
import {SvgIcon, SvgIconProps} from "@material-ui/core";
const importAll = (r: any) => {
const images: any = {};
r.keys().forEach((item: any) => { images[item.replace('./', '').replace(/\.(svg)$/, "")] = r(item).default; });
return images;
};
export const dynamicIcons = importAll(require.context('!@svgr/webpack!../../assets/icons', false, /\.(svg)$/));
type CustomSvgIconProps = Omit<SvgIconProps, "component"> & { icon: string; };
const CustomSvgIcon = ({icon, ...rest}: CustomSvgIconProps) => (
<SvgIcon component={dynamicIcons[`${icon}`]} {...rest}/>
);
Or
import * as React from "react";
import {SvgIcon, SvgIconProps} from "@material-ui/core";
const importAll = (r: any) => {
const images: any = {};
r.keys().forEach((key: any) => {
const svgFile = key.replace('./', '');
const svgName = svgFile.replace(/\.(svg)$/, "");
import(/* webpackMode: "eager" */ `!@svgr/webpack!../../assets/icons/${svgFile}`).then(module => {
images[svgName] = module.default;
});
});
return images;
};
dynamicIcons = importAll(require.context('../../assets/icons', false, /\.(svg)$/));
type CustomSvgIconProps = Omit<SvgIconProps, "component"> & { icon: string; };
const CustomSvgIcon = ({icon, ...rest}: CustomSvgIconProps) => (
<SvgIcon component={dynamicIcons[`${icon}`]} {...rest}/>
);
export default CustomSvgIcon;