Storybook w/ react-router - 你不应该在 <Router> 之外使用 <Link>

Posted

技术标签:

【中文标题】Storybook w/ react-router - 你不应该在 <Router> 之外使用 <Link>【英文标题】:Storybook w/ react-router - You should not use <Link> outside <Router> 【发布时间】:2020-03-13 12:48:24 【问题描述】:

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

虽然我的带有 react-router 的应用程序正常运行,但 Storybook 抛出了错误“Invariant failed: You should not use outside”。

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 文件。 在您的 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" 基于此解决方案here 更多关于全局装饰器here

【讨论】:

这是方式,应该是公认的解决方案 好,我只是将 import react-router 切换到 react-router-dom【参考方案2】:

这对我有用。在 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
;

【讨论】:

【参考方案3】:

对于 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// />;

【讨论】:

【参考方案4】:

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

import StoryRouter from 'storybook-react-router';

addDecorator(StoryRouter());

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

【讨论】:

【参考方案5】:

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

例如,我有一个包含 Link 元素的标题组件,因此在我的 header.stories.tsx 文件中,我将更改以下内容:

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

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

【讨论】:

【参考方案6】:

问题在于 Storybook 呈现各个故事。在这种情况下,使用&lt;Link&gt; 的组件实际上是在&lt;Router&gt; 之外呈现的。

解决方案是使用 addDecorator 用 &lt;Router&gt; 包装各个故事;

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

【讨论】:

以上是关于Storybook w/ react-router - 你不应该在 <Router> 之外使用 <Link>的主要内容,如果未能解决你的问题,请参考以下文章

MUI v5 + Storybook:主题和字体系列在 Storybook 中不起作用

如何使用 Storybook 6 在 Vuetify 中自定义主题?

storybook2 --- React

如何在 Storybook 中显示副标题?

故事书找不到模块'@storybook/angular'[重复]

使用 Nextjs 在 Netlify 上部署 Storybook