Search code examples
react-router-dom

How to migrate to RouterProvider in the case of paraller Routes?


We are trying to migrate RouterProvider to use Data API (ScrollRestoration) in react router dom v6. It is challenging to handle parallel Routes which render two different components under the same path.

I checked and tweaked many examples of single Routes and nested Routes. None of my tries didn't work.

It is hard to find examples similar to this case. How would you migrate to RouterProvider for the following code? The following is the code I am trying to migrate.

App.tsx

function App() {
  return (
    <div className="app">
      <TopNav />
      <div className="title">
        <Routes>
          <Route path="/support" element={<></>} />
          <Route path="/" element={<Title />} />
          <Route path="/:categoryId" element={<Title />} />
          <Route path="/:categoryId/:subcategoryId" element={<Title />} />
          <Route path="/:categoryId/:subcategoryId/:contentId" element={<Title />} />
        </Routes>
      </div>
      <SideNav />
      <div className="content">
        <div className="page-section">
          <main>
            <Routes>
              <Route path="/support" element={<Form />} />
              <Route path="/" element={<Content />} />
              <Route path="/:categoryId" element={<Content />} />
              <Route path="/:categoryId/:subcategoryId" element={<Content />} />
              <Route path="/:categoryId/:subcategoryId/:contentId" element={<Content />} />
            </Routes>
          </main>
          <Footer />
        </div>
      </div>
    </div>
  );
}

index.tsx

ReactDOM.render(
  <React.StrictMode>
    <PrismicProvider client={client}>
     <BrowserRouter>
      <App />
     </BrowserRouter>
    </PrismicProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

Solution

  • This is how I managed to migrate to RouterProvider from BrowserRouter. Refactor the code is necessary to remove some repetitions.

    I created RootLayout, TitleLayout, and ContentLayout. Then, I wrapped Title component with TitleLayout. It goes the same way for the Content component.

    App.tsx

    import { RouterProvider, createBrowserRouter, Outlet, ScrollRestoration } from 'react-router-dom';
    
    import TopNav from './components';
    import Hero from './components';
    import SideNav from './components';
    import Footer from './components';
    import ContentPage from './components';
    import FormPage from './components';
    
    export const router = createBrowserRouter([
      {
        element: <RootLayout />,
        children: [
          {
            path: '/support',
            element: (
              <>
                <TitleLayout>
                  <></>
                </TitleLayout>
                <ContentLayout>
                  <FormPage />
                </ContentLayout>
              </>
            ),
          },
          {
            path: '/',
            element: (
              <>
                <TitleLayout>
                  <Hero />
                </TitleLayout>
                <ContentLayout>
                  <ContentPage />
                </ContentLayout>
              </>
            ),
          },
          {
            path: '/:categoryId',
            element: (
              <>
                <TitleLayout>
                  <Hero />
                </TitleLayout>
                <ContentLayout>
                  <ContentPage />
                </ContentLayout>
              </>
            ),
          },
          {
            path: '/:categoryId/:subcategoryId',
            element: (
              <>
                <TitleLayout>
                  <Hero />
                </TitleLayout>
                <ContentLayout>
                  <ContentPage />
                </ContentLayout>
              </>
            ),
          },
          {
            path: '/:categoryId/:subcategoryId/:contentId',
            element: (
              <>
                <TitleLayout>
                  <Hero />
                </TitleLayout>
                <ContentLayout>
                  <ContentPage />
                </ContentLayout>
              </>
            ),
          },
        ],
      },
    ]);
    
    function RootLayout() {
      return (
        <div className="app">
          <TopNavigation />
          <Outlet />
          <ScrollRestoration />
        </div>
      );
    }
    
    function TitleLayout({ children }: { children: React.ReactNode }) {
      return (
        <>
          <div className="title">{children}</div>
          <SideNavigation />
        </>
      );
    }
    
    function ContentLayout({ children }: { children: React.ReactNode }) {
      return (
        <>
          <div className="content">
            <div className="page-area">
              <main className="page-content">{children}</main>
              <Footer />
            </div>
          </div>
        </>
      );
    }
    
    function App() {
      return <RouterProvider router={router} />;
    }
    
    export default App;
    

    index.tsx

    ReactDOM.render(
      <React.StrictMode>
        <PrismicProvider client={client}>
          <App />
        </PrismicProvider>
      </React.StrictMode>,
      document.getElementById('root')
    );