将 Storybook 与 React 和 Redux 结合使用

Storybook 允许您单独开发 UI 组件,这可以提高组件的重复使用、可测试性和开发速度。

除了这些开发者体验 (DX) 优点外, Storybook 还与传统的组件开发工作得很好,并且不需要对核心功能进行更改,以显示、测试和文档您的组件库。

它还可以通过addonsdecorators提供进一步的扩展。 通过 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.jsApp.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

也看

Published At
Categories with 技术
Tagged with
comments powered by Disqus