You need to enable JavaScript to run this app. Storybook 6装饰器向Story传递props失效(state/setState为undefined)
优惠活动
大模型
产品
解决方案
定价
更多

Storybook 6装饰器向Story传递props失效(state/setState为undefined)

问题核心原因

Storybook v6 对 CSF 格式 Story 的参数注入逻辑做了破坏性调整:
v5 中直接给 <Story> 组件附加的自定义 props,会自动合并到 Story 函数的入参里;但 v6 之后 Story 函数的入参只会接收定义在 args/argTypes 里的参数,装饰器附加的额外 props 不会被注入到函数解构的 props 对象中,因此你拿到的 state、setState 必然是 undefined。
另外还有个易漏的前置问题:你在 preview.js 中使用了 useState 但没有显式从 React 导入,运行时也会触发异常。

最优解决方案:用 React Context 跨层级传递状态

这是 v6 之后官方推荐的跨装饰器/Story 传自定义值的方式,不会被 Storybook 的参数合并逻辑覆盖。

步骤1:创建共享 Context

新建公共文件(比如 ./.storybook/story-state-context.js):

import { createContext } from 'react';

// 初始值可按需调整
export const StoryStateContext = createContext({
  state: undefined,
  setState: () => {}
});

步骤2:改造全局装饰器

// .storybook/preview.js
import React, { useState } from 'react';
import { StoryStateContext } from './story-state-context';

export const decorators = [
  (Story) => {
    const [state, setState] = useState();
    return (
      <StoryStateContext.Provider value={{ state, setState }}>
        <Story />
      </StoryStateContext.Provider>
    );
  }
];

步骤3:在 Story 中取值

不再从函数入参解构,改用 useContext 读取:

// mycomponent.stories.tsx
import { useContext } from 'react';
import { StoryStateContext } from '../.storybook/story-state-context';

export const TwoButtons = () => {
  const { state, setState } = useContext(StoryStateContext);
  return (
    <ButtonGroup
      buttons={[
        { label: 'One', value: 'one' },
        { label: 'Two', value: 'two' }
      ]}
      selectedButton={state}
      onClick={val => setState(val)}
    />
  );
};
可选方案:手动挂载自定义参数(不推荐)

如果一定要走参数传值逻辑,需要把装饰器生成的状态手动挂到 Storybook 全局上下文上,再在 Story 中读取:

// 全局装饰器改造示例
export const decorators = [
  (Story, context) => {
    const [state, setState] = useState();
    // 把自定义值挂到 Storybook 上下文的 parameters 字段上
    context.parameters.customState = { state, setState };
    return <Story />;
  }
];

// Story 中显式从上下文取值
export const TwoButtons = (args, context) => {
  const { state, setState } = context.parameters.customState;
  return (
    <ButtonGroup
      buttons={[
        { label: 'One', value: 'one' },
        { label: 'Two', value: 'two' }
      ]}
      selectedButton={state}
      onClick={val => setState(val)}
    />
  );
};

这个方案依赖 Storybook 内部参数结构,版本升级时容易出兼容性问题,优先使用 Context 方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.29 14:15:04