4 回答

TA貢獻1856條經驗 獲得超17個贊
導入 SVG 文件時可以使用ref并命名導出。ReactComponent請注意,它必須是ref為了使它工作。
以下示例使用需要版本v16.8及更高版本的 React 鉤子。
示例動態 SVG 導入鉤子:
function useDynamicSVGImport(name, options = {}) {
const ImportedIconRef = useRef();
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const { onCompleted, onError } = options;
useEffect(() => {
setLoading(true);
const importIcon = async () => {
try {
ImportedIconRef.current = (
await import(`./${name}.svg`)
).ReactComponent;
if (onCompleted) {
onCompleted(name, ImportedIconRef.current);
}
} catch (err) {
if (onError) {
onError(err);
}
setError(err);
} finally {
setLoading(false);
}
};
importIcon();
}, [name, onCompleted, onError]);
return { error, loading, SvgIcon: ImportedIconRef.current };
}
打字稿中的示例動態 SVG 導入鉤子:
interface UseDynamicSVGImportOptions {
onCompleted?: (
name: string,
SvgIcon: React.FC<React.SVGProps<SVGSVGElement>> | undefined
) => void;
onError?: (err: Error) => void;
}
function useDynamicSVGImport(
name: string,
options: UseDynamicSVGImportOptions = {}
) {
const ImportedIconRef = useRef<React.FC<React.SVGProps<SVGSVGElement>>>();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error>();
const { onCompleted, onError } = options;
useEffect(() => {
setLoading(true);
const importIcon = async (): Promise<void> => {
try {
ImportedIconRef.current = (
await import(`./${name}.svg`)
).ReactComponent;
onCompleted?.(name, ImportedIconRef.current);
} catch (err) {
onError?.(err);
setError(err);
} finally {
setLoading(false);
}
};
importIcon();
}, [name, onCompleted, onError]);
return { error, loading, SvgIcon: ImportedIconRef.current };
}
對于那些在動態導入 SVG 時得到undefined的人來說ReactComponent,這是由于一個錯誤,即以某種方式將 SVG 添加ReactComponent到每個導入的 SVG 的 Webpack 插件不會在動態導入時觸發。
基于此解決方案,我們可以通過在您的動態 SVG 導入中強制使用相同的加載器來臨時解決它。
唯一的區別是ReactComponent現在是default輸出。
ImportedIconRef.current = (await import(`!!@svgr/webpack?-svgo,+titleProp,+ref!./${name}.svg`)).default;
另請注意,使用帶有可變部分的動態導入時存在限制。這個 SO answer詳細解釋了這個問題。
要解決此問題,您可以使動態導入路徑更加明確。
例如,代替
// App.js
<Icon path="../../icons/icon.svg" />
// Icon.jsx
...
import(path);
...
您可以將其更改為
// App.js
<Icon name="icon" />
// Icon.jsx
...
import(`../../icons/${name}.svg`);
...

TA貢獻1860條經驗 獲得超8個贊
您的渲染函數(用于類組件)和函數組件不應是異步的(因為它們必須返回 DOMNode 或 null - 在您的情況下,它們返回一個 Promise)。相反,您可以以常規方式渲染它們,然后導入圖標并在下一次渲染中使用它。嘗試以下操作:
const Test = () => {
let [icon, setIcon] = useState('');
useEffect(async () => {
let importedIcon = await import('your_path');
setIcon(importedIcon.default);
}, []);
return <img alt='' src={ icon }/>;
};

TA貢獻1842條經驗 獲得超13個贊
我根據答案https://github.com/facebook/create-react-app/issues/5276#issuecomment-665628393進行了更改
export const Icon: FC<IconProps> = ({ name, ...rest }): JSX.Element | null => {
const ImportedIconRef = useRef<FC<SVGProps<SVGSVGElement>> | any>();
const [loading, setLoading] = React.useState(false);
useEffect((): void => {
setLoading(true);
const importIcon = async (): Promise<void> => {
try {
// Changing this line works fine to me
ImportedIconRef.current = (await import(`!!@svgr/webpack?-svgo,+titleProp,+ref!./${name}.svg`)).default;
} catch (err) {
throw err;
} finally {
setLoading(false);
}
};
importIcon();
}, [name]);
if (!loading && ImportedIconRef.current) {
const { current: ImportedIcon } = ImportedIconRef;
return <ImportedIcon {...rest} />;
}
return null;
};

TA貢獻1936條經驗 獲得超7個贊
動態加載 svg 的一種解決方案是使用require將其加載到img中,例如:
<img src={require(`../assets/${logoNameVariable}`)?.default} />
添加回答
舉報