1
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?

All component children of <Routes> must be a <Route> or <React.Fragment>エラーの対処法

1
Posted at

背景

下記の教材を進めていて、React Routerv5での記述方法とv7での記述方法で違う部分があったので記述します

エラー内容

Uncaught Error: [DefaultLayout] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>

DefaultLayout<Route>コンポーネントではない。<Routes>の下に置けるのは<Route>もしくは<React.Fragment>だけだよ

エラーが出たソースコード

// App.jsx
import { Routes, Route } from 'react-router';
import { Top } from '../components/pages/Top';
import { Users } from '../components/pages/Users';
import { DefaultLayout } from '../components/templates/DefaultLayout';

export const Router = () => {
  return (
    <Routes>
      <DefaultLayout>
        <Route path="/" element={<Top />} />
      </DefaultLayout>
      <Route path="/users" element={<Users />} />
    </Routes>
  );
};
// DefaultLayout.jsx
import { Footer } from '../atoms/layout/Footer';
import { Header } from '../atoms/layout/Header';

export const DefaultLayout = (props) => {
  const { children } = props;
  return (
    <>
      <Header />
      {children}
      <Footer />
    </>
  );
};

  • DefaultLayout内ではpropsを利用して、Topページを表示させようとしていた

なぜ<Routes><Route>しか受け付けないのか

<Routes>はレンダリング時に子要素のpathelementなどのpropsを読み取って、ルーティングテーブルを構築している。任意のコンポーネントが子要素に混ざると、このルートマッチングの仕組みが正しく機能しなくなるため、<Route>または<React.Fragment>のみが許可されている

公式ドキュメントでもchildrenの型はNested Route elementsと明記されている

Nested Route elements

んーこれか…笑
どこかに前提知識的な記載がありそうなきもする

正しいソースコード

// App.jsx
import { Routes, Route } from 'react-router';
import { Top } from '../components/pages/Top';
import { Users } from '../components/pages/Users';
import { DefaultLayout } from '../components/templates/DefaultLayout';

export const Router = () => {
  return (
    <Routes>
      <Route element={<DefaultLayout />}>
        <Route path="/" element={<Top />} />
      </Route>
      <Route path="/users" element={<Users />} />
    </Routes>
  );
};
// DefaultLayout.jsx
import { Outlet } from 'react-router';
import { Footer } from '../atoms/layout/Footer';
import { Header } from '../atoms/layout/Header';

export const DefaultLayout = () => {
  return (
    <>
      <Header />
      <Outlet />
      <Footer />
    </>
  );
};

変更点

  • DefaultLayoutコンポーネントもRouteで囲むようにした
  • DefaultLayoutではprops.childrenの代わりにOutletを利用して子ルートの内容を表示するようにした
    • Outletは、親ルート内でマッチした子ルートのコンポーネントをレンダリングするための専用コンポーネント

感想

  • ドキュメントの内容を正確に解釈できていなかった…という点は反省

参考

1
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
1
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?