带反应路由器的故事书 - 你不应该<Link>在外面<Router>使用



发布了一个问题的解决方案,尽管我很难找到Sensei的谷歌搜索技巧。

尽管我的应用程序与反应路由器工作没有任何问题Storybook抛出了错误";不变量失败:您不应该使用<链接>外部<路由器>";。

Error: Invariant failed: You should not use <Link> outside a <Router>
at invariant (tiny-invariant.esm.js:11)
at react-router-dom.js:181
at updateContextConsumer (react-dom.development.js:19747)
at beginWork$1 (react-dom.development.js:20079)
at HTMLUnknownElement.callCallback (react-dom.development.js:358)
at Object.invokeGuardedCallbackDev (react-dom.development.js:410)
at invokeGuardedCallback (react-dom.development.js:463)
at beginWork$$1 (react-dom.development.js:25730)
at performUnitOfWork (react-dom.development.js:24631)
at workLoopSync (react-dom.development.js:24613)

奇怪的是,该应用程序工作正常(因此,在<路由器>之外没有使用<链接>(。

以下是对我有效的方法:

  1. .storybook文件夹中创建一个preview.js文件
  2. preview.js文件中添加以下全局装饰器
import React from "react";
import { addDecorator } from "@storybook/react";
import { MemoryRouter } from "react-router";

addDecorator(story => <MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>);

票据

  • 使用的故事书版本:"@storybook/react": "^5.3.13"
  • 基于此解决方案
  • 点击此处了解更多关于全球装饰师的信息

编辑:Storybook V7更新(2022年12月(

  1. preview.js重命名为preview.tsx(我想它与jsx的工作原理相同,但我的项目是用TypeScript制作的(

  2. addDecorator函数不再适用于v7,所以您需要像这样添加它。

import React from "react";
import { MemoryRouter } from "react-router";

export const decorators = [
(Story) => (
<MemoryRouter initialEntries={['/']}>
<Story />
</MemoryRouter>
),
];

这对我很有用。在decorators属性中添加Memory Router。

import React from 'react';
import {MemoryRouter} from 'react-router-dom';
import //your component// from //component location//
export default {
title : //How you want your component to show in storybook eg: 'Components/Button'
component : //Specify the name of component that you imported eg: 'Button'
decorators : [(Story) => (<MemoryRouter><Story/></MemoryRouter>)] //Wrapping the story inside the router
};

对于6.1版本的Storybook,在新的代码表示法中使用Storybook路由器。以下是单个组件的示例:

import React from 'react';
import StoryRouter from 'storybook-react-router';
import //your component// from //component location//
export default {
title: '//your component//',
component: //your component//,
decorators: [StoryRouter()],
};
export const Name = () => <//your component// />;

进一步了解Web滑雪的答案。将StoryRouter添加到.storybook/preview.js

import StoryRouter from 'storybook-react-router';
addDecorator(StoryRouter());

现在,它在全球范围内,在每个故事中都可以使用。

如果您想对单个组件而不是全局执行此操作,那么在故事文件中,将组件封装在内存路由器中。

例如,我有一个标头组件,它有一个Link元素,所以在我的header.stores.tsx文件中,我会更改以下内容:

const Template: ComponentStory<typeof Header> = (args) => (
<Header {...args} />
);

const Template: ComponentStory<typeof Header> = (args) => (
<MemoryRouter>
<Header {...args} />
</MemoryRouter>
);

Fabian的答案是目前得票最多的答案,只有当你不想在你的故事中使用React Router的数据API时,它才能解决问题。

这是我对Fabian解决方案的修改版本,增加了使用React Router数据API的能力,因此可以使用数据路由器特定的功能,如扩展的Form组件:

import { createMemoryRouter, RouterProvider } from "react-router-dom";
import { addDecorator } from "@storybook/react";
addDecorator((story) => {
const router = createMemoryRouter([{ path: "/", element: story() }], {
initialEntries: ["/"],
});
return <RouterProvider router={router} />;
});

问题是Storybook渲染单个故事。在这种情况下,使用<Link>的组件实际上是在<Router>之外呈现的。

解决方案是使用addDecorator用<Router>包装单个故事;

//config.js
//...
addDecorator(story => <Router>{story()}</Router>);

如果您还想使用路由路径参数,则需要使用故事书装饰器。用户Web-skisidonaldson已经展示了如何将路由器mock添加到故事书中。

以下是我在react v 18 中实现的故事书路由器mock

预览.js文件

import { withRouter } from "storybook-addon-react-router-v6";
export const decorators = [withRouter];

component.story.js文件

import Component from "./component";
export default {
component: Component,
title: "component with rout path and parameters",
parameters: {
reactRouter: {
routePath: "/root/:primary/:secondary",
routeParams: { primary: "firstparam", secondary: "secondparam" },
},
},
};
const Template = (args) => <Component {...args} />;
export const Default = Template.bind({});
Default.args = {
// ommited
};

这将为useParams等函数提供以下结果:

const {primary, secondary} = useParams();
console.log('primary value: ' + primary)
console.log('secondary value: ' + secondary)
// outputs: primary value: firstparam
// outputs: secondary value: secondparam

相关内容

  • 没有找到相关文章

最新更新