如何在 Storybook 中使用 redux-toolkit?

Posted

技术标签:

【中文标题】如何在 Storybook 中使用 redux-toolkit?【英文标题】:How to use redux-toolkit with Storybook? 【发布时间】:2021-07-26 07:47:24 【问题描述】:

我目前正在尝试使用 Storybook 设置 redux-toolkit。但是,当我在故事书中查看它们时,我的选择器在我的组件中返回未定义。当我将我的应用程序作为普通的 React 应用程序运行时,选择器会返回适当的状态。

如何使用 Redux 设置 Storybook,以便我的选择器实际上从商店返回预期状态?

这是我的故事书故事:

import  Meta, Story  from "@storybook/react"
import ContactInfo from "./ContactInfo"
import  Provider  from "react-redux"
import  store  from "../../../store/config/configureStore"

export default 
  title: "Forms/ContactInfo",
  component: ContactInfo,
  decorators: [(story) => <Provider store=store>story()</Provider>],
 as Meta

export const Template: Story<> = (args) => <ContactInfo ...args />

这是我的商店配置

import  configureStore  from "@reduxjs/toolkit"
import  useDispatch  from "react-redux"
import  logger  from "../middleware/logger"
import rootReducer from "./reducer"

const store = configureStore(
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware(
      serializableCheck: false,
      immutableCheck: false,
    ).concat(logger),
)

export  store 

export type AppDispatch = typeof store.dispatch
export const useAppDispatch = () => useDispatch<AppDispatch>()

export type RootState = ReturnType<typeof rootReducer>

export interface GetState 
  getState: () => RootState

这是我的带有选择器的组件

import React from "react"
import  useSelector  from "react-redux"
import  useAppDispatch  from "../../../store/config/configureStore"
import 
  selectContactInfo,
  updateContactInfo,
 from "../../../store/contactInfo"
import Social from "../../components/social/Social"
import TextField from "../../components/textField/TextField"

export default function ContactInfo() 
  const dispatch = useAppDispatch()
  const contactInfo = useSelector(selectContactInfo)

  console.log("printing contactInfo", contactInfo)

  const handleChange = (event: any) => 
    const target = event.target

    const updatedContactInfo =  ...contactInfo, [target.name]: target.value 
    dispatch(updateContactInfo(updatedContactInfo))
  

  const handleSubmit = (event: React.SyntheticEvent) => 
    console.log("User submitted contact info section: ", contactInfo, "yo")
    event.preventDefault()
  

  return (
    <form onSubmit=handleSubmit>
      <h2>Enter Your Contact Information</h2>
      <TextField
        label="First Name"
        value=contactInfo.firstName
        onChange=handleChange
      />

      <TextField
        label="Last Name"
        value=contactInfo.lastName
        onChange=handleChange
      />

      <TextField
        label="Middle Initial"
        value=contactInfo.middleInitial
        onChange=handleChange
        required=false
        maxLength=1
      />

      <TextField
        label="Email Address"
        type="email"
        value=contactInfo.emailAddress
        onChange=handleChange
      />

      <Social socialLinks=contactInfo.socialLinks />

      <TextField
        label="Phone Number"
        type="tel"
        value=contactInfo.phoneNumber
        onChange=handleChange
      />

      <button
        type="button"
        onClick=() => console.log("User wants to go back.")
      >
        Back
      </button>
      <button type="submit">Next</button>
    </form>
  )


【问题讨论】:

【参考方案1】:

要解决此问题,请在您的 .storybook/preview.js 文件中添加一个全局装饰器:

import  Provider  from "react-redux"
import  store  from "../src/store/config/configureStore"

export const parameters = 
  actions:  argTypesRegex: "^on[A-Z].*" ,
  controls: 
    matchers: 
      color: /(background|color)$/i,
      date: /Date$/,
    ,
  ,


export const decorators = [
  (Story) => (
    <Provider store=store>
      <Story />
    </Provider>
  ),
]

2021 年 11 月 26 日更新

通过.storybook/preview.js 添加提供程序(或模拟它)实际上是一个好习惯

As showed in the storybook's screen tutorial

【讨论】:

【参考方案2】:

如上所述,您可以通过 Provider 将您的 redux 存储连接到您的 Story 组件。但实际上这种做法是错误的。

为设计组件而创建的故事书,独立构建您的 UI(如其主页所述)。 不适用于测试商店交互。逻辑和从存储接收数据应该分开放置。当您想在应用程序之外呈现组件时,Storybook 很有用。要测试与 Store 的交互 - 只需使用 react-scripts 或 npm 脚本在应用程序中运行它。

如果您问这个问题 - 可能您的应用程序设计得很糟糕。我会考虑重构。

【讨论】:

以上是关于如何在 Storybook 中使用 redux-toolkit?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Storybook 中添加样式道具作为控件?

如何在 Storybook 中使用 redux-toolkit?

如何在 Storybook 中为 Angular 启用样式源映射

如何导出在 storybook 中创建的 React Native 组件以便在实际应用中使用?

如何使用 Storybook 6 在 Vuetify 中自定义主题?

如何让 Storybook 使用项目的 CSS 变量