React使用动态标签名称

最近在一项目里(React + antd)遇到一个需求,某项基础信息里有个图标配置(图标用的是antd的Icon组件),该项基础信息的图标信息修改后,存于后台数据库,后台数据库里存的是antd Icon组件的图标Tag名称,如AreaChartOutlined PieChartOutlined BarChartOutlined 等,另外在展示页面,需要根据该项信息的Tag名称,显示对应的antd图标。

antd 图标的使用方法

正常情况下安装@ant-design/icons依赖后,就可以在页面中使用antd图标,如:

shell 复制代码
$ npm install @ant-design/icons --save
ts 复制代码
import { HomeOutlined } from '@ant-design/icons';

const App: React.FC = () => (
  <Space>
    <HomeOutlined />
  </Space>
);

但是如果页面中,图标的Tag名称不确定,又如何使用呢?

方案1. 使用React.createElement创建元素

关于React.createElement的详细用法,可以阅读文档:https://react.dev/reference/react/createElement
React.createElement(type, props, ...children) 包含三个参数:

  • type: 该参数必须为一个有效的React组件类型,例如,其可以是一个Tag名称(如div或者span),也可以是一个React组件(一个函数、一个类或者一个特殊组件如Fragment)
  • props: 该参数应是一个对象或者null。如果传递null,则会当成空对象处理。React会创建一个元素,该元素属性与参数props相匹配。
  • optional ...children: 可选参数children。可以传递0个、1个或多个。其可以是ReactNode,包含React组件,字符串,数字,ReactNode,空节点(null, undefined, true, false),或者ReactNode数组。

知道React.createElement用法之后,我们可以进行简单的尝试,代码如下:

ts 复制代码
import React from "react";
import "./index.css";
import * as Icons from "@ant-design/icons"; // 注意要先引入icons
import { Space } from "antd";

function customIcon(tagName: string) {
  return React.createElement(Icons[tagName], {}, null);
}

const App: React.FC = () => (
  <Space>
    {customIcon("AreaChartOutlined ")}
    {customIcon("PieChartOutlined  ")}
    {customIcon("BarChartOutlined  ")}
  </Space>
);

export default App;

完整代码可以在codesandbox里查看:https://codesandbox.io/p/sandbox/react-createelement-chuang-jian-dong-tai-yuan-su-3hndf2?file=%2Fdemo.tsx%3A1%2C1

在codesandbox里我们可以看到,效果和我们预想的一样,正常显示了三个图标:

使用自定义Tag Name

但是对于上述方法,个人感觉有一点点的繁琐。

在一番搜索之下,看到React官方文档里有这么一句话:(链接:https://legacy.reactjs.org/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized

When an element type starts with a lowercase letter, it refers to a built-in component like
or and results in a string 'div' or 'span' passed to React.createElement. Types that start with a capital letter like compile to React.createElement(Foo) and correspond to a component defined or imported in your JavaScript file.

大意是说Tag名称如果以小写 开头,则会指向内置的html组件,例如<div> 或者 <span>,结果将会通过React.createElement创建对应元素,其中type参数为'div'或者'span',如: React.createElement('div');如果Tag名称如果以大写 开头,例如<Foo />,结果则会通过React.createElement(Foo)创建对应的元素,对应的组件则必须在js文件中引入。(这段翻译是我瞎掰的,手动狗头)。

所以我们可以将上面代码中的customIcon方法简化如下:

ts 复制代码
function customIcon(tagName: string) {
  const Icon = Icons[tagName]; // 变量名必须以大写字母开头
  return <Icon />;
}

完整代码如下:

ts 复制代码
import React from "react";
import "./index.css";
import * as Icons from "@ant-design/icons"; // 注意要先引入icons
import { Space } from "antd";

function customIcon(tagName: string) {
  // return React.createElement(Icons[tagName], {}, null);
  const Icon = Icons[tagName]; // 变量名必须以大写字母开头
  return <Icon />;
}

const App: React.FC = () => (
  <Space>
    {customIcon("AreaChartOutlined")}
    {customIcon("PieChartOutlined")}
    {customIcon("BarChartOutlined")}
  </Space>
);

export default App;

完整代码可以在codesandbox里查看:https://codesandbox.io/p/sandbox/custom-tag-name-h7zhyt?file=%2Fdemo.tsx%3A1%2C1

在codesandbox里我们可以看到,效果和之前的效果一模一样,都是显示三个图标。

扩展阅读:
2022年中华人民共和国县以上行政区划代码
react + antd实现动态切换主题功能(适用于antd5.x版本)
常用的几款Vue移动端UI推荐

相关推荐
科技探秘人3 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人4 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR9 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香11 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q24985969314 分钟前
前端预览word、excel、ppt
前端·word·excel
小华同学ai19 分钟前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_91528 分钟前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風6 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫6 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试