Storybook w/ react-router - 你不应该在 <Router> 之外使用 <Link>
Storybook w/ react-router - You should not use <Link> outside <Router>
发布问题的解决方案我很难找到,尽管 Sensei 谷歌搜索技能
尽管我的带有 react-router 的应用程序没有任何问题 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 (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$ (react-dom.development.js:25730)
at performUnitOfWork (react-dom.development.js:24631)
at workLoopSync (react-dom.development.js:24613)
奇怪,因为该应用程序有效(因此没有在外面使用)。
以下是对我有用的方法:
- 在您的
.storybook
文件夹中创建一个 preview.js
文件。
- 在您的
preview.js
文件中添加以下全局装饰器。
import React from "react";
import { addDecorator } from "@storybook/react";
import { MemoryRouter } from "react-router";
addDecorator(story => <MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>);
备注
问题是 Storybook 渲染了各个故事。在这种情况下,使用 <Link>
的组件实际上是在 <Router>
.
之外呈现的
解决方案是使用 addDecorator 用 <Router>
包装单个故事;
//config.js
//...
addDecorator(story => <Router>{story()}</Router>);
这对我有用。在装饰器内添加 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
};
对于 Storybook 6.1 版,storybook-router 采用新的代码表示法。这是单个组件的示例:
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-ski 的回答。将 StoryRouter 添加到您的 .storybook/preview.js
import StoryRouter from 'storybook-react-router';
addDecorator(StoryRouter());
它现在可以在全球范围内的每个故事中使用。
如果您想对单个组件而不是全局执行此操作,则在故事文件中,将组件包装在内存路由器中。
例如,我有一个 header 组件,它有一个 Link 元素,所以在我的 header.stories.tsx 文件中,我将更改以下内容:
const Template: ComponentStory<typeof Header> = (args) => (
<Header {...args} />
);
至
const Template: ComponentStory<typeof Header> = (args) => (
<MemoryRouter>
<Header {...args} />
</MemoryRouter>
);
发布问题的解决方案我很难找到,尽管 Sensei 谷歌搜索技能
尽管我的带有 react-router 的应用程序没有任何问题 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 (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$ (react-dom.development.js:25730)
at performUnitOfWork (react-dom.development.js:24631)
at workLoopSync (react-dom.development.js:24613)
奇怪,因为该应用程序有效(因此没有在外面使用)。
以下是对我有用的方法:
- 在您的
.storybook
文件夹中创建一个preview.js
文件。 - 在您的
preview.js
文件中添加以下全局装饰器。
import React from "react";
import { addDecorator } from "@storybook/react";
import { MemoryRouter } from "react-router";
addDecorator(story => <MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>);
备注
问题是 Storybook 渲染了各个故事。在这种情况下,使用 <Link>
的组件实际上是在 <Router>
.
解决方案是使用 addDecorator 用 <Router>
包装单个故事;
//config.js
//...
addDecorator(story => <Router>{story()}</Router>);
这对我有用。在装饰器内添加 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
};
对于 Storybook 6.1 版,storybook-router 采用新的代码表示法。这是单个组件的示例:
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-ski 的回答。将 StoryRouter 添加到您的 .storybook/preview.js
import StoryRouter from 'storybook-react-router';
addDecorator(StoryRouter());
它现在可以在全球范围内的每个故事中使用。
如果您想对单个组件而不是全局执行此操作,则在故事文件中,将组件包装在内存路由器中。
例如,我有一个 header 组件,它有一个 Link 元素,所以在我的 header.stories.tsx 文件中,我将更改以下内容:
const Template: ComponentStory<typeof Header> = (args) => (
<Header {...args} />
);
至
const Template: ComponentStory<typeof Header> = (args) => (
<MemoryRouter>
<Header {...args} />
</MemoryRouter>
);