返回博客

Storybook Args 简介

下一代,动态组件示例

loading
Michael Shilman
@mshilman
最后更新

Storybook 是世界上最受欢迎的 UI 组件工作坊。它被 Airbnb、Slack、Lyft、IBM、Shopify 以及行业内数千个顶级团队使用。

Storybook 的核心是一个 stories 目录:小的 Javascript 函数,用于捕获隔离的 UI 组件状态,使其在交互式开发、测试和文档方面非常有用。

现在在 Storybook 6.0 中,我们很高兴推出 Storybook Args,这是编写 stories 的一项基础性改进Args 允许 stories 接收动态数据作为输入参数,从而解锁故事 人体工程学、可移植性重用性 的新水平。

Args 与您现有的 stories 兼容,但解锁了新功能

  • 🗜 减少 stories 的大小和复杂性
  • 🚚 在 stories 之间重用 fixture 数据
  • ♻️ 在更广泛的工具中循环使用 stories

它们还为强大的下一代 Storybook 插件打开了大门,我们将在后续系列文章中介绍这些插件。


💡 为什么需要动态数据?

Storybook 的 组件故事格式 (CSF) 是组件示例的新兴标准,在 Storybook 5.2 中引入。CSF 文件是 ES6 模块,没有任何 Storybook 特定的扩展。因此,它们简单、可移植且面向未来

export const Basic = () => (
  <Button label='hello' />
);

编写 CSF story 很简单。您可以在想要显示的状态下实例化组件,将其包装在一个函数中,并命名它。

但这可以改进。Tom Coleman 和我在研究了 CSF 在 45,000 多个 Github 仓库中的使用情况后,有了一个见解:如果 stories 接受动态数据作为输入,它将解锁无数新的用例。

考虑以下我们之前示例的迭代

export const Basic = (args) => <Button {...args} />;
Basic.args = { label: 'hello' };

这个新版本从“环境”接收一个 Args 对象,并声明它想要在该对象中接收的初始数据。

这种间接的技巧可能看起来是件小事,但它是一个强大的抽象,它支撑着下一代 Storybook 功能。在这篇文章中,我们将重点介绍 Args 使编写 stories 更高效的不同方式。

动态数据使您能够实时编辑组件

🗜 减少 story 样板代码

Args 通过在 story 的数据显示逻辑之间提供更清晰的分离,减少了用户需要为每个 story 编写和维护的代码。

考虑以下 CSF v1 stories

// Button.stories.js

export const Text = () => (
  <Button label="hello" background="#ff0" />
);

export const Emoji = () => (
  <Button label="😀 😎 👍 💯" background="#ff0" />
);

现在考虑使用 Args 的相同 stories

// Button.stories.js

const Template = (args) => <Button {...args} />;

export const Text = Template.bind({});
Text.args = { label: 'hello', background: '#ff0' };

export const Emoji = Template.bind({});
Emoji.args = { ...Text.args, label: '😀 😎 👍 💯' };

story 函数样板代码在 stories 之间重用:Template.bind({}) 复制该函数,减少代码重复

同样,...Text.args 复制数据,减少数据重复

当为其他框架编写 stories 时,优势变得更加明显。考虑 Vue 的等效示例

// Button.stories.js

const Template = (args) => ({
  props: Object.keys(args),
  components: { MyButton },
  template: `
    <my-button :background="background">
     {{label}}
    </my-button>
  `
});

export const Text = Template.bind({});
Text.args = { label: 'hello', background: '#ff0' };

export const Emoji = Template.bind({});
Emoji.args = { ...Text.args, label: '😀 😎 👍 💯' };

Args stories 的这种模式与早期的 CSF 版本有所不同,但我们认为您会喜欢它。如果您喜欢以“旧”方式编写 stories,或者逐步采用,Storybook 完全向后兼容。

🚚 在 stories 之间重用 fixture 数据

Args 的第二个主要用户好处是,它提供了一种风格化的方式来组织和共享组件的 fixture 数据。

您可能熟悉编程中的 DRY 原则:不要重复自己。但在实践中,我们在 stories 中看到很多重复。

考虑一个假想任务列表的复合组件

// TaskList.stories.js

const owner = { login: 'shilman', avatar: ... };
export const Basic = () => (
  <TaskList items={[
    { title: 'checked item', checked: true, owner },
    { title: 'checked item', checked: true, owner },
    { title: 'unchecked item', checked: false, owner },
    { title: 'unassigned item', checked: false,  },
  ]}/>
);

现在考虑 Args 等效项

// TaskList.stories.js

import { Checked, Unchecked, Unassigned } from '../Task.stories';

const Template = (args) => <TaskList {...arg} />;

export const Basic = Template.bind({});
Basic.args = { 
  items: [Checked.args, Checked.args, Unchecked.args, Unassigned.args]
};

在 Args 示例中,当 Task 组件的签名更改时,您只需要更改 Tasks stories 以反映新的 schema。因为您的 Args stories 重用 fixture 数据,所以 schema 更改将向上层 story 层次结构传播,从而大大降低维护成本。

这种数据重用在为大型应用程序构建 Storybooks 时特别有用,在这些应用程序中,组件是分层组织的。

Args 的许多设计灵感来自 Chromatic 的 storybook,其中包含数千个 stories,范围从 原子 组件一直到完整的应用程序页面。

Args 将这些学习经验编码到 story 语言本身中,融入了多年来作为顶级从业者开发和使用 Storybook 所获得的宝贵最佳实践。

♻️ 在其他工具中循环使用 stories

最后一个好处是 Args stories 比以前更具可移植性。

组件故事格式的一个设计目标是创建高度可移植的组件示例。在我们的 公告帖子中,我们展示了如何在 Jest 单元测试中循环使用 CSF story,并描绘了前端工具空间中互操作性的更大前景。

随着 CSF 在整个生态系统中的采用,这一愿景现在正在成为现实。它内置于热门的新 React 框架 RedwoodJS 中。它为强大的在线 IDE webcomponents.dev 提供支持。并且截至撰写本文时,它已被纳入至少一种流行的设计工具中。

Args 通过从您的 stories 中删除插件依赖项,使互操作性更进一步。考虑以下 CSF v1 story,它使用了 actionsknobs,这是 Storybook 最受欢迎的两个插件

import { action } from '@storybook/addon-actions';
import { text } from '@storybook/addon-knobs';

export default { title: 'Button' };

export const Text = () => (
  <Button
    onClick={action('onClick')}
    label={text('label', 'Hello')}
  />
);

这个 ES6 模块是可移植的,但它依赖于 @storybook/addon-actions@storybook/addon-knobs,这两者都严重依赖 Storybook 的运行时。

现在考虑 Args 等效项

const Template = (args) => <Button {...args} />;

export const Text = Template.bind({});
Text.args = { label: 'Hello' }

请注意,这个 story 不再依赖于 @storybook/* 包。Args 由“环境”提供,因此即使没有直接的 story 依赖项,我们也可以保留 actions 和 knobs 风格的功能!当我们将在后续文章中介绍自动生成的 controlsactions 时,我们将更详细地解释这是如何工作的。

删除这些 Storybook 依赖项提高了可移植性,因此 story 在外部设计、原型设计、开发和测试工具中更容易使用。

考虑如何将上面的 Args story 在 Jest 中循环使用

import { render, fireEvent } from '@testing-library/react';
import { Text } from './Button.stories';

it('should respond to click events', () => {
  const handleClick = jest.fn();
  
  const instance = render(
    <Text {...Text.args} onClick={handleClick} />
  );
  
  fireEvent.click(instance.container.firstChild);
  expect(handleClick).toHaveBeenCalled();
});

为原始 CSF story 使用 knobs 和 actions 编写相同的测试将需要复杂的模拟。不再需要了!我们很高兴在整个前端生态系统中推广基于 Args 的组件示例。

⚡ 1 分钟安装

在过去几个月使用 args 后,我们认为所有用户都应该立即升级。立即在 Storybook 6.0 中试用!

升级现有的 Storybook 项目

npx sb upgrade

或将 Storybook 引导到现有应用程序中

npx sb init

要创建您的第一个 Args story,请创建一个函数,该函数将 Args 对象作为其第一个输入,然后使用您想要接收的数据注释该函数

import { Button } from '@storybook/react/demo';

export default { title: 'Button/Args', component: Button };

export const Basic = (args) => <Button {...args} />;
Basic.args = { children: 'hello' };

瞧!您已经编写了您的第一个 Args story。但这只是冰山一角。Args 还为插件增压,并为 Storybook 带来了许多新功能,我们将在未来几周内对此进行扩展。

在下面订阅以了解 Args 如何启用


参与进来

Args 由 Michael Shilman (我!) 和 Tom Coleman 开发,灵感来自 addon-docs/knobs/context 贡献者,包括 Norbert de LangenFilipp RiabchunAtanas StoyanovLeo Y. Li

Storybook 由 1000 多名开源贡献者维护,并由顶级维护者的指导委员会指导。如果您有兴趣贡献,请在 GitHub 上查看 Storybook,创建一个 issue,或提交一个 pull request。在 Open Collective 上捐款。在 Discord 中与我们聊天 — 维护者通常在线。

加入 Storybook 邮件列表

获取最新的新闻、更新和发布

6,730位开发者及更多

我们正在招聘!

加入 Storybook 和 Chromatic 背后的团队。构建被数十万开发者在生产环境中使用的工具。远程优先。

查看职位

热门文章

Storybook Controls

无需代码即可实时编辑 UI 组件
loading
Michael Shilman

零配置 Storybook

简单设置,即时生产力
loading
Michael Shilman

Storybook 5.3

更快地构建生产设计系统
loading
Michael Shilman
加入社区
6,730位开发者及更多
为什么为什么选择 Storybook组件驱动的 UI
文档指南教程更新日志遥测
社区插件参与进来博客
展示探索项目组件词汇表
开源软件
Storybook - Storybook 中文

特别感谢 Netlify CircleCI