gvaldambrini / storybook-router

A storybook decorator that allows you to use routing-aware components in your stories
MIT License
258 stars 33 forks source link

Invariant violations when components import from 'react-router-dom' #37

Open MalcolmDwyer opened 5 years ago

MalcolmDwyer commented 5 years ago

Issue: Storybook-router only works when components are importing <Route>, <Link>, etc. from react-router, but fail when importing from react-router-dom.

I'm guessing this is the same problem in #36

Which version are you using?

    "@storybook/react": "^5.0.10",
    "react-router": "^5.0.0",
    "react-router-dom": "^5.0.0",
    "storybook-react-router": "^1.0.5",

Are you using storybook-router with a react based project or a vue one?

React

Please describe the problem:

Getting invariant violation "You should not use <Route> outside a <Router>" (or "...<Link> outside <Router>").

Please explain how to reproduce the issue or (better) provide an example to do it.

I made a simple test story and component, and when the component is importing Route from react-router-dom, I get the invariant violation. If I import from react-router, then it is ok.

import React from 'react';
import { Route } from 'react-router';
// import { Route } from 'react-router-dom'; <--- This is how it should work (?)

const TestRouteComponent = ({ val }) => (
  <div>
    <Route
      path="/:path?"
      render={({ match }) => (
        <div>
          <div style={{ backgroundColor: '#fdd' }}>
            Prop:
            {val}
          </div>
          <div style={{ backgroundColor: '#ddf' }}>
            Route params:
            {JSON.stringify(match.params)}
          </div>
        </div>
      )}
    />
  </div>
);

export default TestRouteComponent;
import React from 'react';
import StoryRouter from 'storybook-react-router';
import { storiesOf } from '@storybook/react';
import TestRouteComponent from './TestRouteComponent';

const storyRouterConfig = [
  {},
  { initialEntries: ['/foo'] },
];

const getRouterDecorator = () => StoryRouter(...storyRouterConfig);

storiesOf('Test', module)
  .addParameters({
    info: 'some info',
  })
  .addDecorator(getRouterDecorator())
  .add('with val = foo', () => (
    <TestRouteComponent val="val" />
  ));
MalcolmDwyer commented 5 years ago

Workaround... not using storybook-router...

import { MemoryRouter as Router } from 'react-router-dom';

.addDecorator(story => (
   <Router initialEntries={['/foo']}>{story()}</Router>
)

I guess my use case is simple, so I don't need the more advanced features of storybook-router.

mechmillan commented 5 years ago

I am seeing the same issue (same versions listed above) after upgrading react-router-dom.

I tried using <Route> directly from react-router as well (at 5.0.0) but I still get the same error message as described above.

gvaldambrini commented 5 years ago

Hi Malcolm, thank you for the report.

Unfortunately I cannot reproduce the issue, even using your code (with a small fix in the component implementation). Can you please check if this works for you (pay attention to use the test-route branch)?

https://github.com/gvaldambrini/react-simple-boilerplate/tree/test-route https://github.com/gvaldambrini/react-simple-boilerplate/tree/test-route

You can just run storybook and you will find your test component there. For me, everything works (with the import of the Route component from react-router-dom).

Gianni

mechmillan commented 5 years ago

I was able to get it working using the following structure when setting up the storybook config:

import StoryRouter from 'storybook-react-router';

const getRouterDecorator = () => StoryRouter();

addDecorator(getRouterDecorator());

I didn't need to set up a storyRouterConfig i.e const storyRouterConfig = [ {}, { initialEntries: ['/foo'] }, ]; per the Test route sample linked above but it is not working if I am using addDecorator(StoryRouter()) directly.

gvaldambrini commented 5 years ago

@mechmillan thank you for your reply and sorry for the delay. Does your post means that you tried with the repo I'd suggested and it didn't work for you unless you wrap the Storyrouter call into an arrow function?

PhilippeLaval commented 5 years ago

Same issue for me. @MalcolmDwyer solution worked perfectly.

gvaldambrini commented 5 years ago

Can someone please share an example (repository) of a project that has this problem? I cannot reproduce the issue in any way. Thanks!

manishparanjape commented 5 years ago

Getting Same error (Please See below) Invariant failed: You should not use <Link> outside a <Router> Error: Invariant failed: You should not use <Link> outside a <Router> at invariant (http://localhost:6006/vendors~main.be47fb506b0b1d887b23.bundle.js:94405:11) at http://localhost:6006/vendors~main.be47fb506b0b1d887b23.bundle.js:89025:88 at updateContextConsumer (http://localhost:6006/vendors~main.be47fb506b0b1d887b23.bundle.js:44922:19) at beginWork (http://localhost:6006/vendors~main.be47fb506b0b1d887b23.bundle.js:45110:14) at performUnitOfWork (http://localhost:6006/vendors~main.be47fb506b0b1d887b23.bundle.js:48750:12) at workLoop (http://localhost:6006/vendors~main.be47fb506b0b1d887b23.bundle.js:48790:24) at renderRoot (http://localhost:6006/vendors~main.be47fb506b0b1d887b23.bundle.js:48873:7) at performWorkOnRoot (http://localhost:6006/vendors~main.be47fb506b0b1d887b23.bundle.js:49780:7) at performWork (http://localhost:6006/vendors~main.be47fb506b0b1d887b23.bundle.js:49692:7) at performSyncWork (http://localhost:6006/vendors~main.be47fb506b0b1d887b23.bundle.js:49666:3)

I get this error for ### Example >> storybook-router/examples/react-router/Links.js

dani2112 commented 5 years ago

Could this be related to changes in react-router when upgrading to v5.0.1? I got the same error when wrapping my component with a MemoryRouter instance from react-router-dom in Storybook. When following advice to re-export react-router-dom from my library for the use in Storybook it works. See also this issue and this issue So could this package suffer from a similar Issue? Probably storybook-router is using a different context, similar to all other components that are currently suffering from this problem and as such does not wrap the Link components correctly.

maxie7 commented 4 years ago

I have

"react-dom": "^16.12.0",
"react-router-dom": "^5.1.2",

then in import import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';

and everything works well, BUT in tests (I use Jest of CreateReactApp) a have this error Invariant failed: You should not use <Link> outside a <Router>

Is this because of react-test-renderer (its version)

The problem is still not resolved

maxie7 commented 4 years ago

the problem is solved. So, in test file: 1) in imports ... import { BrowserRouter as Router } from 'react-router-dom'; 2) in describe...

it(">> upload invoice component matches the snapshot", () => {
    const uploadInvoiceButton = create(
      <Router>
        <UploadInvoiceButton />
      </Router>
    );
    expect(uploadInvoiceButton.toJSON()).toMatchSnapshot();
});