【问题标题】:React + Redux + Storybook: How to use connected react router's useParams when writing storybook stories?React + Redux + Storybook:在编写故事书故事时如何使用连接的 React 路由器的 useParams?
【发布时间】:2021-03-03 13:44:07
【问题描述】:

我有一个 react 组件,它从路由中获取 id 并使用它来加载一些数据并填充 redux 状态。

我正在使用来自“react-router”的useParams 来执行此操作。

import { useParams } from 'react-router'

import { usePreload } from './hooks'
import Display from './Display'

const Overview = () => {
  const { id } = useParams()
  const { data } = usePreload(id) // uses useEffect to preload the data with the given id

  return <Display data={data} />
}

export default Overview

我有一个故事

import Overview from './Overview'

import preloadData from './decorators/preloadData'

export default {
  title: 'Redux/scenes/Overview',
  decorators: [preloadData()],
  component: Overview,
  argTypes: {}
}

const Template = args => <Overview {...args} />

export const Default = Template.bind({})

preloadData 装饰器很简单

import { usePreload } from '../hooks'
import { data } from './fixtures'

const Loaded = ({ children }) => {
  useSubmissionsPreload(data.id) // loads the site data into the state

  return <>{children}</>
}

const preloadData = () => Story => (
  <Loaded>
    <Story />
  </Loaded>
)

export default preloadData

代码在站点中实际运行时一切正常,但在故事中运行时,useParams 的路径中没有 :id 可供选择。

现在我将跳过这个故事,只测试Display 组件,但我的完美主义者要求知道如何让它工作。

【问题讨论】:

    标签: reactjs redux react-router storybook


    【解决方案1】:

    我也遇到了问题,De2ev 的评论为我指明了正确的方向。然而,它并没有直接起作用,我不得不做些细微的改变。最后它使用以下代码:

    import React from "react";
    import { Meta } from "@storybook/react";
    import MyComponent from "./MyComponent";
    import { MemoryRouter, Route} from "react-router-dom";
    
    export default {
        title: "My Title",
        component: MyComponent,
        decorators: [(Story) => (
            <MemoryRouter initialEntries={["/path/58270ae9-c0ce-42e9-b0f6-f1e6fd924cf7"]}>
                <Route path="/path/:myId">
                    <Story />
                </Route>
            </MemoryRouter>)],
    } as Meta;
    
    export const Default = () => <MyComponent />;
    

    【讨论】:

    • 这给了我错误A &lt;Route&gt; is only ever to be used as the child of &lt;Routes&gt; element, never rendered directly. Please wrap your &lt;Route&gt; in a &lt;Routes&gt;.
    • 那是因为您使用的是 v6 — 将您的 包装在 中,您应该没问题。
    【解决方案2】:

    在尝试为其中一页创建故事书时,我们也遇到了类似的挑战。我们在 Medium -> link 上找到了解决方案。所有学分,特别感谢作者。

    解决方案是使用 react-router 中的MemoryRouter

    在我们的解决方案中,我们使用了故事书Decorators,它返回了由 MemoryRouter 和 Router 包装的故事 ->

    return ( &lt;MemoryRouter initialEntries={["/routeName/param"]} &lt;Route component={(routerProps) =&gt; &lt;Story {...routerProps} /&gt;} path="/routeName/:paramName"/&gt; &lt;/MemoryRouter&gt;)

    我希望这对经历过同样挑战的每个人都有帮助。

    【讨论】:

      【解决方案3】:

      我在使用 Storybook 6.3+ 和 React Router 6.00-beta 时遇到了同样的问题,必须将 &lt;Route&gt;&lt;Routes&gt;&lt;/Routes&gt; 包装起来才能正常工作。

      import React from "react";
      import { Meta } from "@storybook/react";
      import MyComponent from "./MyComponent";
      import { MemoryRouter, Routes, Route} from "react-router";
      
      export default {
          title: "My Title",
          component: MyComponent,
          decorators: [(Story) => (
              <MemoryRouter initialEntries={["/path/58270ae9-c0ce-42e9-b0f6-f1e6fd924cf7"]}>
                 <Routes>
                   <Route path="/path/:myId">
                      <Story />
                   </Route>
                 </Routes>
              </MemoryRouter>)],
      } as Meta;
      
      export const Default = () => <MyComponent />;
      

      【讨论】:

        【解决方案4】:

        遇到同样的问题,完成如下

        export default {
              title: 'Common/Templates/Template Rendering',
              component: CasePage
            }
            // ? We create a “template” of how args map to rendering
            const Template: Story<any> = (args: any) => {
              const { path } = args
              return (
                <MemoryRouter initialEntries={path}>
                  <Route
                    component={(routerProps: any) => <CasePage {...routerProps} />}
                    path="/dcp/:caseId"
                  />
                </MemoryRouter>
              )
            }
            
            export const TemplateBoxesRendering = Template.bind({})
            TemplateBoxesRendering.args = { path: ['/dcp/FX77777'] }
            
            export const TemplateBoxes = Template.bind({})
            TemplateBoxes.args = { path: ['/dcp/FX22222'] }
        

        【讨论】:

          猜你喜欢
          • 2022-01-18
          • 2020-02-25
          • 2022-07-22
          • 1970-01-01
          • 2020-06-23
          • 2019-04-09
          • 2019-08-28
          • 2021-09-27
          • 2020-05-21
          相关资源
          最近更新 更多