Storybook父组件故事中如何配置操作子组件控件
问题原因
Storybook 控件面板默认只会识别当前故事绑定组件自身显式声明的入参(props),不会自动穿透读取组件内部嵌套的子组件属性。
你当前的实现中,Header组件没有定义任何对外接收的参数,也没有把外部传入的参数透传给内部的<Logo/>、<Gnb/>、<Login/>子组件,所以Header故事的控制面板为空,和你遇到的现象一致:
而单独的Logo故事里你手动配置了color属性的argTypes,所以可以正常调出颜色选择控件:
实现方案
有两种成熟方案可以实现父组件故事里直接调试子组件属性,按需选择即可:
方案1:手动透传子组件Props(推荐生产环境用)
这个方案无额外依赖,属性可控性强,是组件开发的标准实践:
- 改造
Header.tsx,声明子组件对应的入参,透传给内部子组件
// Header.tsx import { styled } from "@mui/material"; import Logo from "../Logo/Logo"; import Gnb from "../Gnb/Gnb"; import Login from "../Login/Login"; // 直接复用子组件的Props类型,避免重复写类型定义 type HeaderProps = { logoProps?: Partial<React.ComponentProps<typeof Logo>>; gnbProps?: Partial<React.ComponentProps<typeof Gnb>>; loginProps?: Partial<React.ComponentProps<typeof Login>>; }; const HeaderStyled = styled("div")({ display: "flex", justifyContent: "space-between", }); export default function Header({ logoProps = {}, gnbProps = {}, loginProps = {} }: HeaderProps) { return ( <HeaderStyled> <Logo {...logoProps} /> <Gnb {...gnbProps} /> <Login {...loginProps} /> </HeaderStyled> ); }
- 改造
Header.stories.tsx,声明对应控件配置,可直接复用子组件故事里已经写好的argTypes,不用重复写控件规则
// Header.stories.tsx import { ComponentMeta, ComponentStory } from "@storybook/react"; import Header from "./index"; // 引入子组件故事的配置,复用已经写好的控件规则 import LogoStories from "../Logo/Logo.stories"; // Gnb、Login的故事配置同理引入 export default { title: "components/Header", component: Header, argTypes: { // 映射控件到对应子组件的属性字段 "logoProps.color": LogoStories.argTypes.color, // 其余Gnb、Login的属性按相同逻辑添加即可 }, } as ComponentMeta<typeof Header>; const Template: ComponentStory<typeof Header> = (args) => ( <Header {...args} /> ); export const Default = Template.bind({}); Default.args = { logoProps: { color: "#1976D2", }, // 其余子组件默认参数同理添加 };
配置完成后,就能在Header的控制面板看到对应子组件的调整项,修改后实时预览效果。
方案2:声明subcomponents自动收集子组件配置(适合本地快速调试)
如果只是本地调试不想写太多透传代码,可以利用Storybook的subcomponents配置项自动收集子组件的argTypes:
// Header.stories.tsx import { ComponentMeta, ComponentStory } from "@storybook/react"; import Header from "./index"; import Logo from "../Logo/Logo"; import Gnb from "../Gnb/Gnb"; import Login from "../Login/Login"; export default { title: "components/Header", component: Header, // 声明要收集配置的子组件 subcomponents: { Logo, Gnb, Login }, } as ComponentMeta<typeof Header>; const Template: ComponentStory<typeof Header> = (args) => { // 注意:该方式不会自动给原Header内部的子组件传参,需要Header组件支持接收对应props透传 const { logoProps = {}, gnbProps = {}, loginProps = {} } = args as any; return ( <Header logoProps={logoProps} gnbProps={gnbProps} loginProps={loginProps} /> ) }; export const Default = Template.bind({});
注意:这个方案本质还是需要Header组件支持接收对应props透传,只是省了手动写argTypes的步骤,更适合快速调试场景。
内容的提问来源于stack exchange,提问作者Jewoo Ham
相关产品推荐
相关产品推荐

