You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为含嵌套Redux连接子组件的组件编写Storybook故事?

处理Storybook中嵌套Redux连接组件的可行思路

我之前也遇到过类似的场景,原项目组件嵌套了多层Redux连接组件,要做Storybook确实有点头疼。下面给你几个实用的解决方案,你可以根据自己的情况选择:

1. 用Provider包裹+Mock Store(最快实现,无需改组件)

首先明确回答你的疑问:如果在Story里把Parent包裹在Redux Provider中,Grandchild是可以成功连接到Store的。因为Redux的Context是逐层传递的,不管嵌套多少层,只要在Provider范围内的connect组件都能拿到Store实例。

具体做法:

  • 专门为Storybook创建一个mock的Redux Store,只注入Grandchild和Parent需要的state数据就行,不用和生产环境的Store完全一致。比如用@reduxjs/toolkit的configureStore快速构建:
    import { configureStore } from '@reduxjs/toolkit';
    import grandchildSlice from '../path/to/grandchildSlice';
    import parentSlice from '../path/to/parentSlice';
    
    const mockStore = configureStore({
      reducer: {
        parent: parentSlice.reducer,
        grandchild: grandchildSlice.reducer,
      },
      preloadedState: {
        parent: { /* Parent需要的mock数据 */ },
        grandchild: { /* Grandchild需要的mock数据 */ },
      },
    });
    
  • 在Story的decorators里用Provider包裹组件:
    import { Provider } from 'react-redux';
    
    export default {
      title: 'Components/Parent',
      component: Parent,
      decorators: [
        (Story) => (
          <Provider store={mockStore}>
            <Story />
          </Provider>
        ),
      ],
    };
    

这样Parent和Grandchild都能正常连接到mock Store,Story就能正常渲染了。

2. 给深层连接组件添加Props fallback(长期组件驱动优化)

如果想往组件驱动开发的方向靠拢,最好的方式是让深层组件(比如Grandchild)支持通过Props接收数据,而不是完全依赖Redux。

具体步骤:

  • 修改Grandchild组件,添加props参数,当props存在时优先使用props,否则从Redux Store获取:
    // Grandchild.jsx
    import { connect } from 'react-redux';
    
    const Grandchild = ({ dataFromProps, dataFromStore }) => {
      const data = dataFromProps || dataFromStore;
      return <div>{data}</div>;
    };
    
    const mapStateToProps = (state) => ({
      dataFromStore: state.grandchild.data,
    });
    
    export default connect(mapStateToProps)(Grandchild);
    
  • 然后在Story里,通过Parent的子组件逐层传递props到Grandchild。如果Child是Parent的内部组件,你可以用Storybook的args或者直接替换Child组件:
    // Parent.stories.jsx
    export const WithMockDeepData = {
      render: () => (
        <Parent>
          {/* 替换原来的Child,传入mock数据给Grandchild */}
          <Child>
            <Grandchild dataFromProps="Mocked grandchild data" />
          </Child>
        </Parent>
      ),
    };
    

这种方式虽然需要改一点组件代码,但能让组件更灵活,也符合组件驱动开发的思路。

3. Mock Redux的connect函数(完全规避Redux)

如果你完全不想在Story里使用Redux,可以通过mock react-redux的connect方法,让所有连接组件变成纯Props组件。

具体做法:

  • 在你的Story文件顶部添加mock代码:
    jest.mock('react-redux', () => ({
      // 保留其他react-redux的功能,只覆盖connect
      ...jest.requireActual('react-redux'),
      connect: () => (Component) => (props) => <Component {...props} />,
    }));
    

这个mock会让所有connect返回的组件直接接收你传入的props,而不会去连接Redux Store。然后你只需要在Story里给Parent(或者逐层)传入所有需要的props即可:

export const WithoutRedux = {
  args: {
    // Parent需要的props
    parentData: 'Mocked parent data',
    // 如果需要给Grandchild传数据,可以通过子组件透传,或者用React Context
  },
};

注意:这种方式可能需要你手动传入所有原本从Store获取的数据,适合组件结构不复杂的场景。


内容的提问来源于stack exchange,提问作者Firecrystal Scribe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:25:11