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

React使用createElement创建动态SVG组件报错不生效如何解决

问题描述

在React应用中构建FontIcon图标组件,目标是实现动态创建SVG组件的功能,目前已完成SVG资源引入。
预期效果:传入prop指定要展示的SVG标识,即可渲染对应图标。

组件内置SVG资源映射表,逻辑上会校验传入的标识是否存在,不存在则渲染默认SVG。但实际运行时SVG始终无法正常渲染,抛出如下报错:

<data:image/svg.... /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.

相关代码

FontIcon.tsx

import React from "react";
import FasExclamationCircle from "./exclamation-circle.svg";
import FarClock from "./clock.svg";

export const iconTypes: { [key: string]: string } = {
    FarClock: FarClock,
    FasExclamationCircle: FasExclamationCircle,
};

type Props = {
    icon: string;
};

export const FontIcon: React.FC<Props> = ({ icon }) => {
    const SvgIcon = iconTypes[icon] == undefined ? FasExclamationCircle : iconTypes[icon];

    return React.createElement(SvgIcon, {
        className: "some class name",
    });
};

App.tsx(组件使用方式)

import FontIcon from "./FontIcon"

<div><FontIcon icon="FarClock"/></div>

补充测试情况

移除prop选择逻辑,直接传入引入的SVG资源调用createElement依然无法正常工作,测试代码如下:

import React from "react";
import FarClock from "./clock.svg";
      
export const FontIcon: React.FC = () => {
    return React.createElement(FarClock, {
        className: "some class name",
    });
};

问题原因

核心原因是当前构建工具(Vite/Webpack等)默认对SVG文件的处理规则是将SVG转成内联data URI字符串,而非可直接渲染的React组件。把字符串作为组件标签传入React.createElement时,React会将其识别为自定义HTML标签解析,最终抛出标签大小写不合法的报错。

解决方案

根据项目使用的构建工具选择对应处理方式:

方案1:Vite 项目

Vite 内置SVG作为组件导入的支持,只需要在SVG导入路径末尾加?react后缀,即可将SVG导入为React组件:

  1. 修改导入语句:
    import FasExclamationCircle from "./exclamation-circle.svg?react";
    import FarClock from "./clock.svg?react";
    
  2. 修正iconTypes的类型定义,替换原来的string类型,避免TS类型报错:
    export const iconTypes: { [key: string]: React.FC<React.SVGProps<SVGSVGElement>> } = {
        FarClock: FarClock,
        FasExclamationCircle: FasExclamationCircle,
    };
    

修改后组件即可正常渲染,支持通过className传入自定义样式。

方案2:Webpack + Create React App 项目

CRA 内置的SVG组件导入需要使用ReactComponent命名导入语法:

  1. 修改导入语句:
    import { ReactComponent as FasExclamationCircle } from "./exclamation-circle.svg";
    import { ReactComponent as FarClock } from "./clock.svg";
    
  2. 和方案1一致,修正iconTypes的类型定义即可。

方案3:通用兼容写法

如果不想调整导入规则,也可以直接将导入得到的SVG字符串作为img标签的src渲染,不需要将其作为组件传入createElement:

export const FontIcon: React.FC<Props> = ({ icon }) => {
    const svgSrc = iconTypes[icon] ?? FasExclamationCircle;
    return <img src={svgSrc} className="some class name" alt="icon" />
};

这种写法下iconTypes的类型保持{ [key: string]: string }即可,缺点是无法通过className直接修改SVG内部元素的样式。

额外注意:当前FontIcon.tsx使用的是命名导出export const FontIcon,App.tsx中使用默认导入import FontIcon from "./FontIcon"会触发找不到导出的错误,需要改成import { FontIcon } from "./FontIcon",或者在FontIcon.tsx中补充默认导出。


内容的提问来源于stack exchange,提问作者maxfromgermany

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 07:31:27