javascript - Kan jeg importere SVG-filen som en React-komponent med dynamiske import()-uttrykk?
Fra dette svaret fra StackOverflow fikk jeg en løsning på hvordan man importerer SVG som ReactComponent og endrer fargen/bredden deres osv.
Men er det mulig å gjøre det samme for dynamisk import? Min funksjonelle komponent:
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;
I den nåværende implementeringen får jeg feil:
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)
Svar #1
Så vidt jeg kan se, er problemet ditt at du importerer hele filen og prøver å gjengi det som en komponent. Du må legge til nøkkelen/komponentidentifikatoren/konstantnavnet til require. For eksempel, hvis du bruker export default YourSVGComponent, kan du få tilgang til det dynamisk ved å gjøre følgende:
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;
Svar #2
Det er en rekke feil her.
'ReactComponent' refererer til en verdi, men brukes som en type her.
ReactComponent som du ser i det lenkede svaret er faktisk en egenskap til .svg-filen når den lastes av Create React App. Det er en kjempekul funksjon som jeg akkurat lærer om for første gang i dag!
I det eksempelkoden
import { ReactComponent as Logo } from './logo.svg';
Det de gjør, er å ta ReactComponent-egenskapen fra './logo.svg'-importen og gi den nytt navn til Logo.
Din import {ReactComponent} from '*.svg'; gir ikke så mye mening.
Du får feilen «type som verdi» når du bruker ReactComponent som en type fordi det ikke er en type. Typepåstanden du forsøkte å gjøre med .then((Icon as ReactComponent) burde ha vært .then((Icon as React.ComponentType<SomePropsType>).
JSX-elementtypen 'Icon' har ingen konstruksjons- eller kallsignaturer.
La oss ta et øyeblikk for å se hva vi faktisk får fra import-setningen.
import(`../../assets/icons/${name}.svg`).then(console.log);
Du bør se et objekt med tre egenskaper: ReactComponent, default og Url.
{
ReactComponent: ƒ SvgLogo(),
default: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0i...",
Url: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0i..."
}
Den default importen fra svg-filen (som også er Url-egenskapen) er data-URL-en for bildet. Du kan bruke den i en img src-egenskap.
Egenskapen ReactComponent er den vi er ute etter! Det er der Create React App konverterer svg-en til en React-komponent. (Merk: navnet "SvgLogo" avhenger av filnavnet).
Ingenting ble returnert fra render.
Ingenting returneres fra din SvgIcon-funksjon. return-setningen du har er returverdien for then-tilbakekallingen.
Å håndtere en asynkron import er litt trikst, siden du ikke vil ha en verdi ved første rendering. I så fall kan vi returnere null (eller du kan ønske å returnere en plassholder med størrelse).
Her bruker jeg element-tilstanden for å lagre det returnerte elementet. Den starter som null og blir erstattet med <Icon/> etter at det har blitt lastet.
Jeg kaller import inne i en useEffect med avhengigheter på dine props. Når importen er løst, får vi Icon fra res.ReactComponent.
Den avledede typen for Icon er any, noe som kan være greit for deg. Hvis du vil ha en nøyaktig type, kan du bruke den rotete as React.ComponentType<JSX.IntrinsicElements['svg']>; som sier «dette er en React-komponent som tar alle props for et <svg>-element».
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;
