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

如何在StoryBook与React TypeScript中创建动态Material UI Icon原子组件?

解决你的动态Icon组件需求

我来帮你搞定这两个问题,咱们一步一步来:

问题分析

先拆解下你当前实现的核心问题:

  1. 无法动态切换图标:你现在是直接传入已经渲染好的图标元素(比如<AccessTimeIcon />),这种方式相当于把图标实例固定死了,Storybook没法动态替换不同的图标组件。
  2. 样式props不生效:你的MyIcon组件只是把传入的materialIcon原封不动返回,没有把fontSize、color这些props传递给MUI的图标组件,所以样式完全没变化。

解决方案

1. 重构Icon组件,支持传入图标组件并传递props

我们需要把materialIcon的类型从React.ReactElement改成React.ComponentType,这样就能接收图标组件本身,然后在MyIcon内部渲染这个组件时,把所有相关的props传递过去。

修改后的Icon.tsx:

import React from "react";
import type { IconProps } from "@mui/material/Icon";

// 修改props类型,materialIcon接收组件类型而非已渲染元素
interface MyIconProps extends IconProps {
  materialIcon: React.ComponentType<IconProps>;
}

const MyIcon = ({ materialIcon: MaterialIcon, ...props }: MyIconProps) => {
  // 渲染传入的图标组件,并传递所有props(fontSize、color等)
  return <MaterialIcon {...props} />;
};

export default MyIcon;

2. 更新Storybook配置,支持动态切换图标

现在我们可以在Story的argTypes里添加materialIcon的控制项,让它可以选择不同的图标组件,同时修改stories的args,传入组件本身而非实例。

修改后的Icon.stories.tsx:

import React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import MyIcon from "./Icon";
import AccessTimeIcon from "@mui/icons-material/AccessTime";
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
import HomeIcon from "@mui/icons-material/Home"; // 可以加更多图标示例

export default {
  title: "Atoms/MyIcon",
  component: MyIcon,
  argTypes: {
    color: {
      options: ["primary", "secondary", "warning", "error", "info", "success", "action"],
      control: { type: "radio" },
    },
    fontSize: {
      options: ["small", "medium", "large"],
      control: { type: "radio" },
    },
    // 添加materialIcon的控制项,支持选择不同图标
    materialIcon: {
      options: {
        AccessTime: AccessTimeIcon,
        PersonOutline: PersonOutlineIcon,
        Home: HomeIcon,
      },
      control: { type: "select" },
    },
  },
} as ComponentMeta<typeof MyIcon>;

const Template: ComponentStory<typeof MyIcon> = (args) => <MyIcon {...args} />;

export const Default = Template.bind({});
Default.args = {
  fontSize: "medium",
  color: "primary",
  materialIcon: AccessTimeIcon, // 传入组件本身,而非<AccessTimeIcon />
};

// 如果你还需要保留特定的story示例,也可以这样写
export const Person = Template.bind({});
Person.args = {
  fontSize: "large",
  color: "warning",
  materialIcon: PersonOutlineIcon,
};

效果说明

  • 现在你可以在Storybook的controls面板里,通过下拉菜单切换不同的图标组件,完全实现动态效果。
  • fontSize、color等props会被自动传递给MUI的图标组件,样式会根据设置实时变化。
  • 这种方式也更灵活,后续添加新图标只需要在argTypes的materialIcon.options里新增即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 11:17:48