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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 13:24:04