Sassyブログ

好きなことで暮らしを豊かにするブログ

react-router v6 のサブルートのパスが一致しない

現在個人プロジェクトでReactを使って開発しています。

その中で react-router v6 を使用しているのですが、v5とは仕様が変わっていて上手く動かなかったので少し内容を記事に書き起こそうと思います。

まずコンソールに表示されていたメッセージはこちらです。

You rendered descendant <Routes> (or called `useRoutes()`) at "/report" (under <Route path="/report">) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render.

親ルート配下の子ルートをレンダリングしようとしたときに * ワイルドカード指定が無いからパスがマッチせずレンダリングできませんでしたという内容のものです。

手元のコードは以下になります。(記事向けにコード内容をところどころ崩しています)

main.tsx

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route
          path="/"
          element={<App />}
          errorElement={<ErrorPage />}
        />;
        <Route
          path="/hoge"
          element={<HogeRouter />}
          errorElement={<ErrorPage />}
        />
      </Routes>
    </BrowserRouter>
  </React.StrictMode>,
)

Hoge.tsx

export default function Router() {
    const form = useForm()
    return (<Routes>
        <Route
            path="/"
            element={<HogeForm {...form} />}
            errorElement={<ErrorPage />}
        />
        <Route
            path="/result"
            element={<HogeResult formValues={form.formValues} />}
            errorElement={<ErrorPage />}
        />
    </Routes>)
}

上記コード例の様にトップレベルで定義している /hoge というパスは子ルートを持っています。

子ルートは /hoge/resultというパスです。

/hogeではHogeFormというコンポーネントレンダリングされ、/hoge/resultではHogeResultというコンポーネントレンダリングされる想定だったのですが、これでは上手く動きません。

なぜかというとreact-router v6 ではexact propsが廃止されデフォルトが完全一致になってしまっているからです。

この影響についてはドキュメントにも記載されています。

is gone. Instead, routes with descendant routes (defined in other components) use a trailing * in their path to indicate they match deeply

出典元:react-router 公式ドキュメント

reactrouter.com

ちょうどv5からのマイグレーションガイドに記載されていました。

デフォルトが完全一致となったため、そのコンポーネントの中に子ルートがある場合は親ルートのパスに /* を指定してあげて、その下階層にも一致するパスがあることを教えてあげます。

なので掲載したコード例の以下の部分に

path="/hoge"

/*を付けてあげて

path="/hoge/*"

とすると、/hoge/resultが見つかり、HogeResultコンポーネントレンダリングされるようになります。

めでたし