React中如何在Storybook中优雅演示connected组件?
可行的低侵入性解决方案
这里提供两种不需要修改原有组件代码、也不用拆分组件层的方案,完全保留connected组件的开发效率,同时满足Storybook多状态展示的需求:
方案1:Mock 自定义Hook + Args 控制状态
你代码里的请求逻辑封装在useFetch自定义Hook中,可以直接在Story文件中Mock这个Hook的返回值,再通过Storybook的args动态控制所有状态:
- 可以自定义任意请求的返回数据、loading状态、报错状态
- 可以通过wrapper组件直接控制
Search组件的初始搜索关键词,无需模拟用户输入
示例story代码如下:
import { Search, AutoCompleteSearchBar, SearchResults, SearchRecommendations } from './Search'; import { useState } from 'react'; // 导入你的自定义Hook import { useFetch } from './hooks/useFetch'; // Mock自定义Hook jest.mock('./hooks/useFetch'); export default { title: 'Components/Search', component: Search, argTypes: { initialSearch: { control: 'text', defaultValue: '' }, suggestions: { control: 'object', defaultValue: ['react', 'vue', 'angular'] }, results: { control: 'object', defaultValue: ['React 入门教程', 'React 最佳实践'] }, recommendations: { control: 'object', defaultValue: ['React 源码解析', 'React 性能优化'] }, isLoading: { control: 'boolean', defaultValue: false }, isError: { control: 'boolean', defaultValue: false }, } }; const Template = (args) => { // 根据args动态设置useFetch的返回值 useFetch.mockImplementation((url) => { if (args.isError) return { error: new Error('请求失败') }; if (args.isLoading) return {}; if (url === '/suggestions') return { suggestions: args.suggestions }; if (url === '/search') return { results: args.results }; if (url === '/recommendations') return { recommendations: args.recommendations }; return {}; }); // 包装原组件注入初始搜索值 const WrappedSearch = () => { const [search, setSearch] = useState(args.initialSearch); return <> <AutoCompleteSearchBar search={search} onChange={setSearch}/> <SearchResults search={search}/> <SearchRecommendations search={search}/> </> }; return <WrappedSearch />; }; // 空状态 export const Empty = Template.bind({}); Empty.args = { initialSearch: '', suggestions: [], results: [], recommendations: [], }; // 加载中状态 export const Loading = Template.bind({}); Loading.args = { initialSearch: 'react', isLoading: true, }; // 报错状态 export const Error = Template.bind({}); Error.args = { initialSearch: 'react', isError: true, }; // 正常返回结果状态 export const Success = Template.bind({}); Success.args = { initialSearch: 'react', };
这种方案你可以直接在Storybook的控制面板里修改所有参数,实时预览不同状态,完全不需要修改原有组件的任何代码。
方案2:Play 函数模拟真实用户交互
如果要完全模拟用户真实使用流程(比如用户输入关键词后触发搜索的完整流程),可以搭配Storybook的play函数和MSW接口Mock工具实现:
- 用MSW mock所有接口的返回,和真实请求逻辑完全一致
- 用
play函数自动触发输入框的输入、回车等用户操作 - 可以模拟请求延时、报错等各种边缘场景,展示的状态和生产环境完全一致
这种方案连Hook都不需要Mock,所有原有逻辑都可以复用,只需要在Story层面加接口Mock和交互模拟代码即可。
内容的提问来源于stack exchange,提问作者Scott Rippey
相关产品推荐
相关产品推荐

