0Pricing
React Academy · 课时

编写 CSF3 故事

使用 Component Story Format 3 导出默认元对象和具名故事。

编写 CSF3 故事 是 CoddyKit 上的免费 React Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Academy 课程共包含 4 节课。

什么是 CSF3

组件故事格式 3(CSF3)是当前的 Storybook 故事格式。故事是普通的 JavaScript/TypeScript 对象,在简单情况下无需渲染函数。

元数据导出

每个故事文件都必须有一个默认导出,即 Meta 对象,用于描述组件并设置共享的故事配置。

import type { Meta } from '@storybook/react';
import { Button } from './Button';

const meta: Meta<typeof Button> = {
  title: 'UI/Button',     // Storybook sidebar path
  component: Button,
  tags: ['autodocs'],     // enables auto-generated docs page
};

export default meta;

命名故事导出

文件中的每个命名导出都是一个故事。在 CSF3 中,故事是一个带有 args 属性的对象(即组件的属性)。

import type { StoryObj } from '@storybook/react';

type Story = StoryObj<typeof Button>;

export const Primary: Story = {
  args: { label: 'Click me', variant: 'primary' },
};

export const Secondary: Story = {
  args: { label: 'Cancel', variant: 'secondary' },
};

export const Disabled: Story = {
  args: { label: 'Unavailable', disabled: true },
};

故事继承

故事会从 meta 对象继承参数。在 meta.args 中设置共享默认值,并根据需要为每个故事进行覆盖。

const meta: Meta<typeof Button> = {
  component: Button,
  args: {
    onClick: fn(), // from @storybook/test
    disabled: false,
  },
};

export const Large: Story = {
  args: { size: 'large', label: 'Large Button' }, // merges with meta args
};

覆盖渲染函数

对于需要自定义 JSX 包裹内容或多个实例的复杂情况,可以在故事中提供 render 函数。

export const WithIcon: Story = {
  render: (args) => (
    <div style={{ display: 'flex', gap: 8 }}>
      <Button {...args} icon={<StarIcon />} />
      <Button {...args} icon={<HeartIcon />} />
    </div>
  ),
  args: { label: 'Action' },
};

单个故事的装饰器

向故事添加 decorators 数组,即可仅为该故事添加额外的提供者或布局。

export const InsideCard: Story = {
  decorators: [
    (Story) => (
      <div style={{ padding: 24, background: '#f5f5f5' }}>
        <Story />
      </div>
    ),
  ],
  args: { label: 'Card Button' },
};

故事参数

使用 parameters 按故事配置插件,例如为特定状态设置背景或视口。

export const DarkMode: Story = {
  parameters: {
    backgrounds: { default: 'dark' },
  },
  args: { label: 'Dark Button', variant: 'primary' },
};

autodocs 标签

将 tags: ['autodocs'] 添加到元数据后,会根据所有命名故事自动生成包含属性表和实时示例的文档页面。

为每种状态编写故事

为每种有意义的组件状态编写一个故事:空、加载中、错误、单个项目、多个项目、RTL 布局等。

export const Loading: Story = { args: { isLoading: true } };
export const Error: Story = { args: { error: 'Failed to load' } };
export const Empty: Story = { args: { items: [] } };
export const WithData: Story = { args: { items: mockUsers } };

命名约定

使用描述状态的 PascalCase 故事名称。避免使用 Default 这样的通用名称,而应具体说明:PrimaryDisabled、SecondaryWithIcon。

使用 title 对故事分组

元数据中的 title 使用斜杠表示法在 Storybook 侧边栏中创建嵌套分组:'Forms/Input' 会创建 Forms 分组及其下的 Input 子组。

const meta: Meta<typeof TextInput> = {
  title: 'Forms/TextInput',
  component: TextInput,
};
// Sidebar: Forms → TextInput → Primary, Error, Disabled...

在测试中复用故事

CSF3 故事是普通对象,因此您可以在单元测试或其他故事中导入并组合它们。

import { Primary } from './Button.stories';

test('renders primary button', () => {
  render(<Button {...Primary.args} />);
  expect(screen.getByText('Click me')).toBeInTheDocument();
});

快速检查

在 CSF3 中,如何定义故事的属性或状态?

回顾

CSF3 故事是带类型的对象,并包含 args。在 meta.args 中设置共享默认值,按故事进行覆盖,使用 render 编写自定义 JSX,并添加 tags: ['autodocs'] 生成自动文档。为每种有意义的组件状态编写一个故事。

常见问题解答

「编写 CSF3 故事」课时是免费的吗?

是的 — 「编写 CSF3 故事」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Academy 课程共包含 4 节课。

「编写 CSF3 故事」这节课中我会学到什么?

使用 Component Story Format 3 导出默认元对象和具名故事。 你通过在浏览器中直接运行的动手代码来练习 React Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 React Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 React Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「编写 CSF3 故事」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 React Academy 课中编写并运行代码吗?

能。每节 React Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 在 React 项目中设置 Storybook
  2. 编写 CSF3 故事
  3. Args、Controls 与 Actions 插件
  4. Storybook 测试与视觉回归
← 返回 React Academy