You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React动态加载SVG组件出现运行时错误,寻求技术帮助

解决React动态加载SVG组件的运行时错误

我来帮你分析下问题出在哪,以及怎么修复:

问题根源

你遇到的错误主要来自三个关键点:

  1. 初始渲染时组件未加载完成:ImportedIconRef.current一开始是undefined,这时候直接渲染<SvgIcon />相当于让React渲染undefined,自然会抛出元素类型无效的错误。
  2. useRef不会触发重渲染:就算异步导入完成后更新了ImportedIconRef.current,组件也不会重新渲染,所以永远显示不了加载好的SVG组件。
  3. (可选)SVG导入配置可能缺失:如果你的构建工具(Webpack/Vite)没有配置SVG作为React组件导入,(await import(...)).ReactComponent会是undefined,也会导致同样的错误。

修复后的代码

我们改用useState来跟踪加载状态和导入的组件,同时添加加载/错误兜底:

import React, { useEffect, useState } from "react";
import { IIcon } from './IIcon';
import { DEFAULT_ASSET_ICON_FOLDER, } from '@/constants/default';

// 可以定义一个兜底的空组件或者错误图标组件
const FallbackIcon = () => <span>⚠️</span>;

function Icon({name}: IIcon) {
  // 用state跟踪导入的组件和加载状态
  const [SvgIcon, setSvgIcon] = useState<React.FC | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [hasError, setHasError] = useState(false);

  useEffect(() => {
    const importIcon = async () => {
      setIsLoading(true);
      setHasError(false);
      try {
        // 确保你的构建工具配置了导出ReactComponent
        const importedModule = await import(`${DEFAULT_ASSET_ICON_FOLDER}/${name}.svg`);
        // 有些配置下可能是default导出,这里可以根据实际情况调整
        const iconComponent = importedModule.ReactComponent || importedModule.default;
        setSvgIcon(iconComponent);
      } catch (err) {
        console.error(`Failed to load icon: ${name}`, err);
        setHasError(true);
      } finally {
        setIsLoading(false);
      }
    };
    // 如果name为空,直接跳过加载
    if (name) {
      importIcon();
    } else {
      setIsLoading(false);
      setHasError(true);
    }
  }, [name]);

  // 加载中、错误、未加载完成时的兜底处理
  if (isLoading) return <span>Loading...</span>;
  if (hasError || !SvgIcon) return <FallbackIcon />;

  return <SvgIcon />;
}

export default Icon;

关键改动说明

  • 用useState替代useRef:state的更新会触发组件重渲染,这样当SVG组件加载完成后,组件会自动更新并渲染正确的图标。
  • 添加加载/错误状态:避免初始渲染时的undefined问题,同时给用户反馈加载状态或错误情况。
  • 兼容不同的导出方式:有些构建工具配置下,SVG组件可能是default导出,所以我们加了importedModule.ReactComponent || importedModule.default的兼容处理。

构建工具配置检查

确保你的项目构建工具正确配置了SVG转React组件:

  • Webpack:需要安装@svgr/webpack,并在webpack配置中添加规则:
    module.exports = {
      module: {
        rules: [
          {
            test: /\.svg$/i,
            issuer: /\.[jt]sx?$/,
            use: ['@svgr/webpack'],
          },
        ],
      },
    };
    
  • Vite:可以安装@vitejs/plugin-react-svg,并在vite.config.ts中配置:
    import { defineConfig } from 'vite';
    import react from '@vitejs/plugin-react';
    import reactSvgPlugin from '@vitejs/plugin-react-svg';
    
    export default defineConfig({
      plugins: [react(), reactSvgPlugin({
        defaultExport: 'component' // 确保导出的是React组件
      })],
    });
    

这样修改后,你的<Icon name="DELETE" />应该就能正常工作了!

内容的提问来源于stack exchange,提问作者Peter J Harrison

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 22:07:40