0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【備忘録】React Routerを使う画面をStorybookで表示する

0
Posted at

背景

Reactアプリの画面をStorybookで表示するとき、アプリ本体で提供しているルーターやレイアウトが必要になった。

アプリはcreateBrowserRouterとRouterProviderを使用し、共通レイアウトにはOutletがある。画面やヘッダーではuseNavigate、useMatchesなどを使う。

Storybook用にcreateMemoryRouterでルートを用意する方針をメモしておく。

コード例の前提

  • React 18系
  • React Router 6系
  • Storybook 8系の@storybook/react-vite

以下は説明用の最小構成。アプリ固有の認証処理やAPI呼び出しは含めない。

Storybookにもルート構造を用意する

// withAppLayoutForStorybook.tsx
import type { Decorator } from '@storybook/react';
import {
  createMemoryRouter,
  RouterProvider,
} from 'react-router-dom';
import { AppLayout } from './AppLayout';

export const withAppLayoutForStorybook: Decorator = (Story) => {
  const router = createMemoryRouter(
      [
        {
          path: '/',
          element: <AppLayout />,
          children: [
            {
              path: 'stock',
              element: <Story />,
              handle: { title: '在庫検索' },
            },
          ],
        },
      ],
      { initialEntries: ['/stock'] }
  );
  return <RouterProvider router={router} />;
};

AppLayoutのexport形式と、handleのプロパティ名は実装に合わせる。この例では名前付きexportとhandle.titleを想定している。

この最小例ではデコレーターの再実行時にルーターを作り直すため、Controlsの変更などで遷移状態が初期化される。遷移状態を保持する必要があれば、ルーターの保持方法を別途設計する。

React Router公式では、createMemoryRouterはStorybookなどの環境にも使えるメモリ上のルーターとして説明されている。

Story側で指定する

import type { Meta, StoryObj } from '@storybook/react';
import { StockSearch } from './StockSearch';
import { withAppLayoutForStorybook } from './withAppLayoutForStorybook';

const meta = {
  title: 'Pages/StockSearch',
  component: StockSearch,
  decorators: [withAppLayoutForStorybook],
} satisfies Meta<typeof StockSearch>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {};

この例もコンポーネントのexport形式に合わせて変更する。

確認すること

  • レイアウト内にOutletがあるか
  • initialEntriesとルート定義が一致しているか
  • ヘッダーが参照するhandleを設定しているか
  • 画面の遷移先が必要なら、そのルートも定義しているか
  • ReduxやDialogProviderなど、ほかのProviderが必要か
  • Controlsでargsを変えたときに表示が更新されるか

アプリ本体のルート定義をそのまま読み込むと、ヘルスチェックや認証、API通信まで動くことがある。画面の確認に必要な構成を決めてから再利用する。

このサンプルは最小構成の例であり、当時のプロジェクトでそのまま動作確認した実装ではない。

次回のためのメモ

ルーターを付けるだけでなく、対象画面が依存するレイアウト・ルート情報・Providerを揃える。

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?