Storybook 允许您单独开发 UI 组件,这可以提高组件的重复使用、可测试性和开发速度。
除了这些开发者体验 (DX) 优点外, Storybook 还与传统的组件开发工作得很好,并且不需要对核心功能进行更改,以显示、测试和文档您的组件库。
它还可以通过addons
和decorators
提供进一步的扩展。 通过 Addons,与您的开发流程网格 Storybook的可能性被解锁。
使用React的故事书
使用 Storybook 进行响应并运行是相对简单的。完整的安装说明在 官方文件中可用。 此过程将提供一个 .storybook/
目录和一个 config.js
文件。
1//in Button.story.js
2
3import React from 'react'
4import { storiesOf } from '@storybook/react'
5
6import Button from './Button'
7
8storiesOf('Button', module)
9 .add('default', () => (
10 <Button>Submit</Button>
11 ))
1//in .storybook/config.js
2
3import { configure } from '@storybook/react'
4
5configure(function() {
6 require('../src/components/Button.story')
7}, module)
1$ npm run storybook
运行启动 Storybook 的命令将在 Stories 面板中显示新的故事。
供应商组件
由于 Storybook 将我们的组件单独呈现,因此可能会出现重现我们应用程序可能提供的高级功能的一些问题,通常在Root.js
或App.js
中找到。
要连接这一点而不修改组件代码,我们将使用 Storybook 提供的辅助程序来创建 Decorators. Decorators允许组件被包装在共同代码中,避免冗余和不一致。
在潜入装饰师之前,我们将从所有高级供应商中创建一个供应商组件,这可能像出口Redux供应商一样简单,但还可以包括路由器、国际化设置等。
1//in Provider.js
2
3import React from 'react'
4import { Router } from 'react-router'
5import { Provider } from 'react-redux'
6
7const ProviderWrapper = ({ children, store }) => (
8 <Provider store={store}>
9 <Router>
10 { children }
11 </Router>
12 </Provider>
13)
14
15export default ProviderWrapper
随着提供商与根分开,它可以很容易地导入到任何组件故事中。
除了导入供应商,我们还需要导入并通过我们Redux商店的实例。
1//in Button.story.js
2
3...
4
5import { storiesOf } from '@storybook/react'
6
7import Provider from '../Provider.js'
8import configureStore from '../configuedStore.js'
9
10const store = configureStore()
11
12...
13
14storiesOf('Button', module)
这使故事可以轻松访问store.dispatch
,因此可以调用 Redux 操作来模拟我们组件的状态变化。
装饰家
Storybook Decorators允许故事以常见的代码包装,该组件可能需要正确执行。 一个常见的例子是包装器以中心页面中的组件,但我们将使用装饰器将提供商组件注入我们的故事,就像 HOC一样。
一个简单的实施将是如下。
1//in Button.story.js
2
3// ...
4
5import Provider from '../Provider.js'
6import configureStore from '../configuedStore.js'
7
8const store = configureStore()
9
10const withProvider = (story) => (
11 <Provider store={store}>
12 { story() }
13 </Provider>
14)
15
16storiesOf('Button', module)
17 .addDecorator(withProvider)
18 .add('default', () => (
19 <Button>Submit</Button>
20 ))
这个与Provider
的装饰器可以转化为用于其他故事的实用功能,为了方便,这些装饰器通常保存在一个新的.storybook/decorators.js
文件中,以便在整个代码库中导入。
世界杯(https://storybook.js.org/addons/using-addons/#global-configuration)
作为额外的帮助, Storybook 提供了一种方法,可以轻松地将装饰品应用到全球所有故事中,这可以通过在.storybook/config.js 中拨打addDecorator
来实现
1//in .storybook/config.js
2
3import { configure, addDecorator } from '@storybook/react'
4import { withProvider } from './decorators'
5
6// ...
7
8addDecorator(withProvider)
进化
減少 DevTools
Redux DevTools是与Redux开发时的动力
,为状态变化,动作重复等提供视觉。
安装 浏览器扩展后,商店中需要一些代码配置。
1//in configureStore.js
2
3import { createStore, applyMiddleware } from 'redux'
4import { composeWithDevTools } from 'redux-devtools-extension'
5
6const store = createStore(reducer, composeWithDevTools(
7 applyMiddleware(...middleware),
8))
在过去,Redux DevTools曾有过与Storybook合作的困难,因为它将所有组件隔离成一个iframe,这阻止了扩展在我们的故事中聆听Redux的行动。
虽然这不再是一个问题,但有一些 Addons 被创建以帮助。
添加
Storybook Native Addons将进一步的开发功能添加到 Storybook. 这些可以是社区撰写的扩展或定制到您的开发流程中。
在问题被更直接地解决之前,这个Redux DevTools倾听器添加程序恢复了组件与浏览器扩展的连接,还为 Storybook 本身添加了一个简单的面板。
配置看起来像这样的东西:
1//in .storybook/addons.js
2
3import 'storybook-addon-redux-listener/register'
1//in configureStore.js
2
3import createStorybookListener from 'storybook-addon-redux-listener'
4
5...
6
7const middlewares = []
8
9// OPTIONAL: attach when Storybook is active
10if (process.env.NODE_ENV === 'storybook') {
11 const reduxListener = createStorybookListener()
12 middlewares.push(reduxListener)
13}
14
15const createStoreWithMiddleware = (reducers) => {
16 return createStore(reducers, applyMiddleware(...middlewares))
17}
18
19const configureStore = () => createStoreWithMiddleware(reducers)
20
21export default configureStore
【转载】【转载】【转载】
这个附加程序添加了多个自定义面板,重现了DevTools的一些功能。
1//in .storybook/addons.js
2
3import addons from '@storybook/addons'
4import registerRedux from 'addon-redux/register'
5
6registerRedux(addons)
1//in configureStore.js
2
3import { createStore, compose } from 'redux'
4import reducer from './your/reducer'
5import withReduxEnhancer from 'addon-redux/enhancer'
6
7const configureStore = () => createStore(reducer, withReduxEnhancer)
8
9export default configureStore