如何为含嵌套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
相关产品推荐
相关产品推荐

