React Router Migration From V5 to V6: A Comprehensive Guide 🚀
Tags: react, reactrouter
Published: 2023-12-27 06:36:55

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
```
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>
   );
 }
```
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>
    )
  }
```

`<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 <Switch> elements to <Routes>:

```
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>
  );
}
```
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

```
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-*
```

```
## 👉 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();
     // ...
  }
```

## 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>
  );
}
```
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>
  );
}
```
## Use `<Navigate>` instead of `<Redirect>`:
From (v5) :

```
<Redirect to="about" />
<Redirect to="home" push />
```
to (v6) :

```
<Navigate to="about" replace />
<Navigate to="home" />
```

## 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>
```
## Remove `<Prompt>`💔: 
`<Prompt>` from v5 is not currently suppported in v6

## 👉 Remove the compatibility package

```
npm uninstall react-router-dom-v5-compat
```

## 👉 Uninstall react-router and history

```
npm uninstall react-router history
```

## 👉 Install React Router v6

```
npm install react-router-dom@6
```


### 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>
    );
  }
```
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 🙏