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组件:
- 修改导入语句:
import FasExclamationCircle from "./exclamation-circle.svg?react"; import FarClock from "./clock.svg?react"; - 修正
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命名导入语法:
- 修改导入语句:
import { ReactComponent as FasExclamationCircle } from "./exclamation-circle.svg"; import { ReactComponent as FarClock } from "./clock.svg"; - 和方案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

