DEV Community

Cover image for React Router Migration From V5 to V6: A Comprehensive Guide πŸš€
k.Jyothi Prakash Reddy
k.Jyothi Prakash Reddy

Posted on

React Router Migration From V5 to V6: A Comprehensive Guide πŸš€

The react-router-dom-v5-compat package enables React Router web apps to incrementally migrate to the latest API in v6 by running it in parallel with v5. It is a copy of v6 with an extra couple of components to keep the two in sync

Incremental Migration

Instead of upgrading and updating all of our code at once (which is incredibly difficult and may cause bugs), we planned to release the react-router migration in two phases...

It looks something like this:

  • Setup the CompatRouter
  • Change a <Route> inside of a <Switch> to a <CompatRoute>
  • Update all APIs inside this route element tree to v6 APIs one at a time
  • Repeat for all routes in the <Switch>
  • Convert the <Switch> to a <Routes>
  • Repeat for all ancestor <Switch>s
  • Update <Links> You're done!

Phase 1: πŸ“ˆ

npm install react-router-dom-v5-compat
Enter fullscreen mode Exit fullscreen mode

Install a Compatibility Package that is react-router-dom-v5-compat - This package includes the v6 API so that you can run it in parallel with v5. (This package helps migrate our code stages instead of making a big, and risky upgrade in our app )

import { BrowserRouter } from "react-router-dom";
import { CompatRouter } from "react-router-dom-v5-compat";

 export function App() {
   return (
     <BrowserRouter>
      <CompatRouter>
         <Switch>
           <Route path="/" exact component={Home} />
           {/* ... */}
         </Switch>
      </CompatRouter>
     </BrowserRouter>
   );
 }
Enter fullscreen mode Exit fullscreen mode

CompatRouter that synchronizes the v5 and v6 APIs state so that both APIs are available.

Done πŸ’₯... We ready for migration

Phase 2:πŸ—ΊοΈ

Convert <Route> to <CompatRoute>

 import { Route } from "react-router-dom";
 import { CompatRoute } from "react-router-dom-v5-compat";

  export function SomComp() {
    return (
      <Switch>
       <Route path="/project/:id" component={Project} />
       <CompatRoute path="/project/:id" component={Project} />
      </Switch>
    )
  }
Enter fullscreen mode Exit fullscreen mode

<CompatRoute> renders a v5 <Route> wrapped inside of a v6 context. This is the special sauce that makes both APIs available to the component tree inside of this route.

then Migrate below React Router APIs

Upgrade all elements to :

function App() {
  return (
    <BrowserRouter>  
      <Switch>
        <Route exact path="/">
          <Home />
        </Route>
        <Route path="/products">
          <Products />
        </Route>
      </Switch>
 </BrowserRouter>   
)}

function Products() {
  let match = useRouteMatch();
  return (
    <div>
      <Link to={`${match.url}/me`}>My Profile</Link>
      <Switch>
        <Route path={`${match.path}/me`}>
          <Own />
        </Route>
        <Route path={`${match.path}/:id`}>
          <UserProfile />
        </Route>
      </Switch>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

to (v6) :

function App() {
  return (
    <BrowserRouter>   
  <Routes>
        <Route path="/" element={<Home />} />
        <Route path="users/*" element={<Products />} />  
   </Routes>
    </BrowserRouter>   
)}


function Products() {
  return (
    <div>
      <nav>
        <Link to="me">My Profile</Link>
      </nav>

      <Routes>
        <Route path=":id" element={<Product />} />
        <Route path="me" element={<OwnUserProfile />} />
      </Routes>
    </div>
  );
}

We don’t use Component as a child anymore instead we will use Component in the element props

### what are the changes? βœ…
* change all the `<Switch>` to `<Routes>`
* All `<Route>`s and `<Link>`s inside a `<Routes>` are relative. This leads to leaner and more predictable code in `<Route path>` and `<Link to>` 
* `<Route exact>` is gone. Instead, `<Route>` automatically finds the exact matches, and use a  * in their end of the path to indicate they match deeply

Enter fullscreen mode Exit fullscreen mode

Valid route paths:
/groups
/groups/admin
/users/:id
/users/:id/messages
/files/*
/files/:id/*

Invalid route paths:
/users/:id?
/tweets/:id(\d+)
/files//cat.jpg
/files-


Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Read from v6 useParams() instead of v5 props.match

+ import { useParams } from "react-router-dom-v5-compat";

function Project(props) {
-    const { params } = props.match;
+    const params = useParams();
     // ...
  }
Enter fullscreen mode Exit fullscreen mode

Use β€˜useNavigate()’ instead of β€˜useHistory()’:

From (v5) :

import { useHistory } from "react-router-dom";

function App() {
  let history = useHistory();
  function gotoHome() {
    history.push("/home");
  }
  function backToLogin() {
    history.replace("/login");
  }
  return (
    <div>
      <button onClick={gotoHome}>go to Home</button
      <button onClick={backToLogin}>login</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

to (v6) :

import { useNavigate } from "react-router-dom";

function App() {
  let navigate = useNavigate();
 function gotoHome() {
    navigate("/home");
  }
  function backToLogin() {
    navigate("/login", { replace: true });
  }
  return (
    <div>
      <button onClick={gotoHome}>go to Home</button
      <button onClick={backToLogin}>login</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Use <Navigate> instead of <Redirect>:

From (v5) :

<Redirect to="about" />
<Redirect to="home" push />
Enter fullscreen mode Exit fullscreen mode

to (v6) :

<Navigate to="about" replace />
<Navigate to="home" />
Enter fullscreen mode Exit fullscreen mode

Replace useRouteMatch with useMatch:

useMatch is very similar to v5's useRouteMatch

NavLink ActiveClassName removed:

<NavLink
  to="/messages"
  className="nav-link"
  activeClassName="activated"
  className={({ isActive }) => "nav-link" + (isActive ? " activated" : "")}
>
  Messages
</NavLink>
Enter fullscreen mode Exit fullscreen mode

Remove <Prompt>πŸ’”:

<Prompt> from v5 is not currently suppported in v6

πŸ‘‰ Remove the compatibility package

npm uninstall react-router-dom-v5-compat
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Uninstall react-router and history

npm uninstall react-router history
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Install React Router v6

npm install react-router-dom@6
Enter fullscreen mode Exit fullscreen mode

Phase 3: πŸš€

Once we migrated all of our code we can remove all the <CompatRoute>, <CompatRouter> and compatibility package (react-router-dom-v5-compat) and install React Router DOM v6 directly.

import { BrowserRouter } from "react-router-dom";

  export function App() {
    return (
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<Home />} />
          {/* ... */}
        </Routes>
      </BrowserRouter>
    );
  }
Enter fullscreen mode Exit fullscreen mode

Finally, we fully migrated to React Router V6 πŸŽ‰ πŸŽ‰

Don't forget to comment down if you're stuck, add your own tips, and help others with their questions πŸ™

Top comments (0)