Posted at

react-routerに依存したコンポーネントをStorybookに追加する

More than 1 year has passed since last update.


問題

例えば、次のようなコンポーネントをStorybookに追加すると


Header

import React from 'react';

import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { Toolbar as RebassToolbar, NavLink } from 'rebass';

import Logo from './Logo';

const Toolbar = styled(RebassToolbar)`
padding: 0 20px 0 20px;
`
;

const NavLinks = styled.div`
margin: auto 12px;
`
;

const Header = () => (
<Toolbar>
<Logo>Takus</Logo>
<NavLinks>
<NavLink to="/" is={Link} children="ホーム" />
<NavLink to="/posts" is={Link} children="一覧" />
</NavLinks>
</Toolbar>
);

export default Header;



Header.stories

import React from 'react';

import { storiesOf } from '@storybook/react';

import Header from './Header';

storiesOf('Header', module).add('default', () => <Header />);


次のようなエラーが発生する


You should not use <Link> outside a <Router>


react-routerのLinkをRouterでWrapされたコンポーネント外で使っているためにエラーが発生している


解決策

storiesOf に生えている addDecorator というAPIを使って、対象のコンポーネントを MemoryRouter でWarpします。react-routerのドキュメントTestingにもある通り、テスト時にルータのコンテキストをスタブする用途で使われるようです。


Header

import React from 'react';

import { MemoryRouter } from 'react-router'
import { storiesOf } from '@storybook/react';

import Header from './Header';

storiesOf('Header', module)
.addDecorator(story => (
<MemoryRouter initialEntries={['/', 'posts']}>{story()}</MemoryRouter>
))
.add('default', () => <Header />);


initialEntriesというプロパティには、対象のコンポーネントがLinkのto で指定しているパスをダミーとして登録しておきます。


参考

https://github.com/storybooks/storybook/issues/769

https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/MemoryRouter.md

https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/testing.md