
Storybook Args 介紹
新一代動態元件範例

Storybook 是世界上最受歡迎的 UI 元件工作坊。它被 Airbnb、Slack、Lyft、IBM、Shopify 以及業界數千個頂尖團隊所使用。
在其核心,Storybook 是一個故事的目錄:小的 Javascript 函數,捕捉隔離的 UI 元件狀態,使其對於互動式開發、測試和文件編寫非常有用。
現在在 Storybook 6.0 中,我們很高興推出 Storybook Args,這是編寫故事的一個基礎性改進。Args 允許故事接收動態數據作為輸入參數,解鎖故事易用性、可移植性和重複使用性的新層次。
Args 與您現有的故事相容,但解鎖了新功能
- 🗜 減少 故事的大小和複雜性
- 🚚 重複使用 跨故事的 fixture 數據
- ♻️ 在更廣泛的工具中重複利用 故事
它們還為強大的下一代 Storybook 插件打開了大門,我們將在一系列後續文章中介紹這些插件。
💡 為什麼需要動態數據?
Storybook 的 元件故事格式 (CSF) 是元件範例的新興標準,在 Storybook 5.2 中引入。CSF 檔案是 ES6 模組,沒有任何 Storybook 特定的擴展。因此,它們簡單、可移植且面向未來
export const Basic = () => (
<Button label='hello' />
);
編寫 CSF 故事很容易。您在想要顯示的狀態下實例化您的元件,將其包裹在一個函數中,並命名它。
但它可以被改進。Tom Coleman 和我在研究了 CSF 在 45,000 多個 Github 倉庫中的使用方式後,有了一個洞察:如果故事接受動態數據作為輸入,它將解鎖無數新的用例。
考慮我們之前範例的以下迭代
export const Basic = (args) => <Button {...args} />;
Basic.args = { label: 'hello' };
這個新版本從「環境」接收一個 Args 物件,並宣告它想要在該物件中接收的初始數據。
這種間接的技巧可能看起來是一件小事,但它是一個強大的抽象概念,支撐著下一代 Storybook 功能。在這篇文章中,我們將重點介紹 Args 使編寫故事更有效率的不同方式。

🗜 減少故事樣板程式碼
Args 透過在故事的數據和顯示邏輯之間提供更清晰的分隔,減少了使用者需要為每個故事編寫和維護的程式碼。
考慮以下 CSF v1 故事
// Button.stories.js
export const Text = () => (
<Button label="hello" background="#ff0" />
);
export const Emoji = () => (
<Button label="😀 😎 👍 💯" background="#ff0" />
);
現在考慮使用 Args 的相同故事
// 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: '😀 😎 👍 💯' };
故事函數樣板程式碼在故事之間重複使用:Template.bind({})
複製了該函數,減少了程式碼重複。
同樣地,...Text.args
複製了數據,減少了數據重複。
當為其他框架編寫故事時,好處變得更加明顯。考慮 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 故事的這種模式與早期的 CSF 版本有所不同,但我們認為您會喜歡它。如果您喜歡以「舊」方式編寫故事,或逐步採用,Storybook 完全向後相容。
🚚 重複使用跨故事的 fixture 數據
Args 的第二個主要使用者好處是,它提供了一種風格化的方式來組織和分享元件的 fixture 數據。
您可能熟悉程式設計中的 DRY 原則:不要重複自己。但在實踐中,我們在故事中看到了很多重複。
考慮一個用於假設任務列表的複合元件
// 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 故事以反映新的架構。由於您的 Args 故事重複使用 fixture 數據,因此架構變更將向上傳播到故事層次結構中,從而大幅降低維護成本。
當為大型應用程式建構 Storybook 時,這種數據重複使用特別有用,在這些應用程式中,元件是按層次結構組織的。
Args 的許多設計靈感來自 Chromatic 的 storybook,其中包含數千個故事,範圍從 原子化 元件一直到完整的應用程式頁面。
Args 將這些學習成果編碼到故事語言本身中,融入了多年來作為頂尖實踐者開發和使用 Storybook 而來之不易的最佳實踐。
♻️ 在其他工具中重複利用故事
最後一個好處是 Args 故事比以前更具可移植性。
元件故事格式的一個設計目標是創建高度可移植的元件範例。在我們的公告文章中,我們展示了如何在 Jest 單元測試中重複利用 CSF 故事,並描繪了前端工具空間中互操作性的更大願景。
隨著 CSF 在整個生態系統中被採用,這個願景現在正在成為現實。它內建於熱門的新 React 框架 RedwoodJS 中。它為 webcomponents.dev 提供支持,這是一個強大的線上 IDE。並且截至撰寫本文時,它已被納入至少一個流行的設計工具中。
Args 透過從您的故事中移除插件依賴性,將互操作性更進一步。考慮以下 CSF v1 故事,它使用了 actions 和 knobs,這是 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' }
請注意,這個故事不再依賴 @storybook/*
套件。Args 由「環境」提供,因此即使沒有直接的故事依賴性,我們也可以保留 actions 和 knobs 風格的功能!我們將在後續文章中介紹自動生成的控制項和動作時,更詳細地解釋這是如何運作的。
移除這些 Storybook 依賴性提高了可移植性,因此故事在外部設計、原型設計、開發和測試工具中更容易使用。
考慮如何在上文中提到的 Args 故事在 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();
});
使用 knobs 和 actions 為原始 CSF 故事編寫相同的測試將需要複雜的模擬。不再需要了!我們很高興在前端生態系統中推廣基於 Args 的元件範例。
⚡ 1 分鐘安裝
在使用 args 的過去幾個月中,我們認為所有使用者都應該立即升級。立即在 Storybook 6.0 中試用!
升級現有的 Storybook 專案
npx sb upgrade
或將 Storybook 啟動到現有的應用程式中
npx sb init
要創建您的第一個 Args 故事,請創建一個函數,該函數將 Args 物件作為其第一個輸入,然後使用您想要接收的數據註釋該函數
import { Button } from '@storybook/react/demo';
export default { title: 'Button/Args', component: Button };
export const Basic = (args) => <Button {...args} />;
Basic.args = { children: 'hello' };
Voilà!您已經編寫了您的第一個 Args 故事。但這只是冰山一角。Args 也為插件增強了功能,並為 Storybook 帶來了許多新功能,我們將在未來幾週內對此進行擴展。
在下方訂閱以了解 Args 如何啟用
- 🎛 自動生成 控制項 用於元件屬性,
- 📢 自動生成動作 用於事件記錄,
- 🛠 自訂工具列 用於主題、國際化和上下文。
參與其中
Args 由 Michael Shilman(我!)和 Tom Coleman 開發,靈感來自 addon-docs
/knobs
/context
貢獻者,包括 Norbert de Langen、Filipp Riabchun、Atanas Stoyanov 和 Leo Y. Li。
Storybook 由 1000 多名開源貢獻者維護,並由頂級維護者的指導委員會指導。如果您有興趣貢獻,請查看 GitHub 上的 Storybook,創建 issue,或提交 pull request。在 Open Collective 上捐款。在 Discord 中與我們聊天 — 通常會有維護者在線上。