繁体   English   中英

我可以将 SVG 文件导入为具有动态 import() 表达式的 React 组件吗?

[英]Can i import the SVG file as a react component with dynamic import() Expressions?

从 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)

我建议您使用process.env.PUBLIC_URL来呈现您的 svg。将所有 svg 文件放在public文件夹中,假设在public/svgFiles中。

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

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

我认为使用 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 图标,我现在没有任何解决方案。 如果我有什么好主意。 我会再次在这里发帖。

据我所知,您的问题是您正在导入整个文件并尝试将其呈现为一个组件,您需要将 append 密钥/组件标识符/常量名称添加到要求中。 例如,如果您使用 export defualt 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.

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

在该示例代码

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

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

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

ReactComponent用作类型时会出现“类型作为值”错误,因为它不是类型。 您尝试使用.then((Icon as ReactComponent)进行的类型断言应该是 .then .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);

您应该看到一个 object 具有三个属性: ReactComponentdefaultUrl

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

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

ReactComponent是我们所追求的属性。 这就是 Create React App 将 svg 转换为 React 组件的地方:(注意,名称“SvgLogo”取决于文件的名称)。

Nothing was returned from render.

您的SvgIcon function 没有返回任何内容。您拥有的return语句是then回调的返回。

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

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

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

Icon的推断类型是any ,这可能适合您。 如果你想要一个准确的类型,你可以使用凌乱as React.ComponentType<JSX.IntrinsicElements['svg']>; 它说“这是一个 React 组件,它采用<svg>元素的所有道具”。

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;
import MyIcon from '../../assets/icons/${name}.svg'

<MyIcon />

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM