Search code examples
javascriptreactjsreact-routerreact-router-dom

<Routes> won't render component that behave as an container of many <Route>


I get this warning when I wrapped my component in <Routes>.

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

App.js

const App = () => {
   return (
        <div className="app__container">
            <Header />
            <Nav />
            <BrowserRouter>
                <Routes>
                    {/* This two component get warning */}
                    <Categories />
                    <Details />      
                </Routes>
            </BrowserRouter>
        </div>
    )
}

Categories.js

const Categories = () => {
  return (
    <>    
        <Route path="/" element={<Navigate replace to="/movie" />} />    

        <Route path="/movie" element={<Movies /> } />
        <Route path="/tv" element={<Tv />}/>
        <Route path="/person" element={<People />} />
        <Route path="/search" element={<Search />} />
    </>
  )
}

Details.js

const Details = () => {
  return (
    <>
        <Route path="/movie/:tmdbID" element={<MovieDetail />}/>
        <Route path="/tv/:tmdbID" element={<TvDetail />}/>
        <Route path="/person/:tmdbID" element={<PersonDetail/>}/>
    </>
  )
}

As you can see, it seems like <Routes> won't take just Categories and Details as a children.

I'm doing it because I want the Route to be placed in different folder/file. Which in Categories.js and Details.js

So, how can I manage this?


Solution

  • The Routes component can only have Route or React.Fragment as valid children. Neither Categories or Details can be rendered directly by Routes like this.

    Render all the routes together as in the following:

    const App = () => {
      return (
        <div className="app__container">
          <BrowserRouter>
            <Header />
            <Nav />
            <Routes>
              <Route path="/" element={<Navigate replace to="/movie" />} />
              <Route path="/search" element={<Search />} />
    
              <Route path="/movie">
                <Route index element={<Movies /> } />
                <Route path=":tmdbID" element={<MovieDetail />} />
              </Route>
    
              <Route path="/tv">
                <Route index element={<Tv />} />
                <Route path=":tmdbID" element={<TvDetail />} />
              </Route>
    
              <Route path="/person">
                <Route index element={<People />} />
                <Route path=":tmdbID" element={<PersonDetail/>} />
              </Route>
            </Routes>
          </BrowserRouter>
        </div>
      );
    };
    

    This organization uses nested routes.

    Or if you are trying to code-split you can split the routes logically by routes/sub-routes where components render descendent routes. In order for descendent routes to work the parent route path appends a wildcard matcher, or splat, "*" to its path and the routed component renders another Routes and set of Route components.

    const MovieRoutes = () => (
      <Routes>
        <Route path="/" element={<Movies /> } />
        <Route path="/:tmdbID" element={<MovieDetail />} />
      </Routes>
    );
    
    const TvRoutes = () => (
      <Routes>
        <Route path="/" element={<Tv />} />
        <Route path="/:tmdbID" element={<TvDetail />} />
      </Routes>
    );
    
    const PersonRoutes = () => (
      <Routes>
        <Route path="/" element={<People />} />
        <Route path="/:tmdbID" element={<PersonDetail/>} />
      </Routes>
    );
    
    const App = () => {
      return (
        <div className="app__container">
          <BrowserRouter>
            <Header />
            <Nav />
            <Routes>
              <Route path="/" element={<Navigate replace to="/movie" />} />
              <Route path="/search" element={<Search />} />
    
              <Route path="/movie/*" element={<MovieRoutes />} />
              <Route path="/tv/*" element={<TvRoutes />} />
              <Route path="/person/*" element={<PersonRoutes />} />
            </Routes>
          </BrowserRouter>
        </div>
      );
    };