我可以使用动态import()表达式将SVG文件作为react组件导入吗



从stackoverflow的这个答案中,我得到了一个关于如何将svg导入为ReactComponent并更改其颜色/宽度等的解决方案。

但是,对于动态导入,是否也可以这样做?我的功能组件:

import * as React from 'react';
import SvgIconComponent from './SvgIcon.Interface';
import {ReactComponent} from '*.svg';
const SvgIcon: React.FC<SvgIconComponent> =({width, color, name}) =>
{
import(`../../assets/icons/${name}.svg`).then((Icon) => {
return <Icon fill={color} width={width}/>
});
};
export default SvgIcon;

在当前的实现中,我得到了错误:

TS2749: 'ReactComponent' refers to a value, but is being used as a type here. // .then((Icon as ReactComponent)
TS2604: JSX element type 'Icon' does not have any construct or call signatures. // .then(Icon)

我认为使用React组件制作颜色和宽度的动态图标是更好的方法。

我添加了我的示例代码:

export const TwitterIcon = ({color, width}: Props) => (
<svg
width={width ? width : 24}
height={width ? width : 24}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill={color ? color : "#1f1f1f"}
d="M8.0798 19.9998C9.55849 20.0493 11.0321 19.8018 12.4135 19.2721C13.795 18.7424 15.0562 17.9411 16.1227 16.9156C17.1892 15.8901 18.0393 14.6613 18.6228 13.3017C19.2063 11.9421 19.5113 10.4793 19.5198 8.9998C20.1974 8.16121 20.7006 7.19563 20.9998 6.1598C21.0221 6.07796 21.0203 5.99141 20.9946 5.91057C20.9689 5.82974 20.9203 5.75806 20.8548 5.70417C20.7893 5.65027 20.7096 5.61647 20.6253 5.60683C20.5411 5.59718 20.4558 5.6121 20.3798 5.6498C20.0253 5.82045 19.6262 5.87558 19.2386 5.80741C18.8511 5.73923 18.4948 5.5512 18.2198 5.2698C17.8687 4.88538 17.4441 4.57533 16.971 4.35803C16.498 4.14072 15.9861 4.02059 15.4657 4.00473C14.9454 3.98888 14.4272 4.07763 13.9417 4.26574C13.4563 4.45384 13.0136 4.73746 12.6398 5.0998C12.128 5.59546 11.7531 6.21509 11.5516 6.89847C11.3501 7.58186 11.3288 8.30575 11.4898 8.9998C8.1398 9.1998 5.8398 7.6098 3.9998 5.4298C3.94452 5.3672 3.87221 5.32205 3.7917 5.29987C3.71119 5.27769 3.62596 5.27943 3.54642 5.30488C3.46688 5.33033 3.39648 5.37839 3.3438 5.4432C3.29113 5.508 3.25846 5.58674 3.2498 5.6698C2.89927 7.61422 3.15213 9.61935 3.97442 11.4159C4.7967 13.2124 6.14904 14.7143 7.8498 15.7198C6.70943 17.0276 5.10801 17.8445 3.3798 17.9998C3.28721 18.0152 3.20174 18.0591 3.13535 18.1254C3.06896 18.1917 3.02497 18.2772 3.00954 18.3698C2.99411 18.4623 3.00801 18.5574 3.0493 18.6417C3.09059 18.726 3.15719 18.7952 3.2398 18.8398C4.74332 19.5912 6.39903 19.988 8.0798 19.9998Z"
/>
</svg>
);

如果你想让图标库

interface IconProps {
keyword: string; //make the clear type to make switch
color: string;
width: number;
}
const SvgIcon = ({keyword, color, width}: IconProps) => {
// In this case you have to think about the switch and types in typescript.
return (
{
'twitter': <TwitterIcon color={color} width={width}/>,
'facebook': <FacebookIcon color={color} width={width}/>,
}[keyword]
)
}
//in component
<SvgIcon keyword='twitter' width={24} color='red'/>

如果你有太多的SVG图标,我现在手头没有任何解决方案。如果我有什么好主意的话。我会再次在这里发帖。

从我所看到的问题来看,您正在导入整个文件,并试图将其呈现为组件,您需要将键/组件标识符/常量名称附加到require中。例如,如果您使用export-devalt YourSVGComponent,您可以通过执行以下操作动态访问它;

import * as React from 'react';
import SvgIconComponent from './SvgIcon.Interface';
const SvgIcon: React.FC<SvgIconComponent> =({width, color, name}) =>
{
const Icon = require(`../../assets/icons/${name}.svg`).default
return <Icon fill={color} width={width}/>
};
export default SvgIcon;

这里有很多错误。

'ReactComponent' refers to a value, but is being used as a type here.

当Create React App加载.svg文件时,您在链接答案中看到的ReactComponent实际上是该文件的一个属性。这是一个超级整洁的功能,我今天才第一次了解它!

在该示例中,代码

import { ReactComponent as Logo } from './logo.svg';

他们正在做的是从'./logo.svg'导入中获取ReactComponent属性,并将其重命名为Logo

你的import {ReactComponent} from '*.svg';没有多大意义。

你得到了";type as value";将ReactComponent用作类型时出错,因为它不是类型。您试图使用.then((Icon as ReactComponent)进行的类型断言应该是.then((Icon as React.ComponentType<SomePropsType>)

JSX element type 'Icon' does not have any construct or call signatures.

让我们花点时间看看我们从import语句中实际得到了什么。

import(`../../assets/icons/${name}.svg`).then(console.log);

您应该看到一个具有三个属性的对象:ReactComponentdefaultUrl

{
ReactComponent: ƒ SvgLogo(),
default: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0i...",
Url: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0i..."
}

从svg文件导入的default(也是Url属性(是图像的数据url。您可以在imgsrc属性中使用它。

ReactComponent是我们追求的财产!这就是Create React App将svg转换为React组件的地方。(注意:"SvgLogo"的名称取决于文件的名称(。

Nothing was returned from render.

SvgIcon函数不会返回任何内容。您拥有的return语句是then回调的返回。

处理异步import有点棘手,因为第一次渲染时没有值。在这种情况下,我们可以返回null(或者您可能想要返回一个大小的占位符(。

这里我使用element状态来存储返回的元素。它从null开始,加载后被<Icon/>替换。

我在一个依赖于你道具的useEffect中调用import。导入解析后,我们从res.ReactComponent中获得Icon

推断出的Icon的类型是any,这对您来说可能很好。如果你想要一个准确的类型,你可以使用杂乱的as React.ComponentType<JSX.IntrinsicElements['svg']>;,上面写着";这是一个React组件,它采用CCD_;。

import * as React from "react";
interface SVGIconProps {
width: string | number;
color: string;
name: string;
}
const SvgIcon: React.FC<SVGIconProps> = ({ width, color, name }) => {
const [element, setElement] = React.useState<JSX.Element | null>(null);
React.useEffect(() => {
import(`./icons/${name}.svg`).then((res) => {
const Icon = res.ReactComponent as React.ComponentType<JSX.IntrinsicElements['svg']>;
setElement(<Icon fill={color} width={width} />);
});
}, [name, color, width]);
return element;
};
export default SvgIcon;

我建议您使用process.env.PUBLIC_URL来渲染您的svg。将所有svg文件都放在public文件夹中,比如说放在public/svgFiles中。

然后可以将其用作<img src={process.env.PUBLIC_URL + "/svgFiles/" + file_name} alt="project" />

由于公用文件夹中的所有内容都包含在最终的build中,因此您的所有svg文件以及您使用的路径都将得到处理,因为所有内容都将从公用文件夹中引用,因此在构建后不会更改路径。


进近2

以这种方式导入SVG作为react组件:

import { ReactComponent as MY_SVG_COMPONENT } from '/path/to/svg'

现在,您可以传递SVGComponent中可用的所有道具,如

<MY_SVG_COMPONENT className="my-svg-class" />
import MyIcon from '../../assets/icons/${name}.svg'
<MyIcon />

最新更新