Transition from React Router v5 to v6

Posted by TempleDMDKrazd on Fri, 14 Jan 2022 06:02:11 +0100

React router is the standard library of routes in react js. It allows users of the react application to move between different parts (components) of the application.

The React router team announced that it would release a stable version of React router version 6 (v6) by the end of 2021. However, due to some major API changes, it may be difficult to switch from React router version 5 (v5) to v6 In this article, we will introduce the new features in v6 and how to upgrade the existing React project from v5 to v6.

To upgrade the version of the react router package in our application, we navigate to the project folder and run

npm install react-router-dom@[VERSION_NUMBER]

Replace VERSION_NUMBER is the version we want to install, or if we want the latest version, replace it with "latest", as shown below:

npm install react-router-dom@6

perhaps

npm install react-router-dom@latest

Please note that we must be connected to the Internet to complete the installation, otherwise the installation will fail. Also, make sure that the react version in the project is V16.0 8 or later because react router V6 relies heavily on react V16 8 initially supported hooks

Switch es are replaced with Routes

The first thing to be replaced in the v5 era was the Switch component. The Switch component is used to wrap our route, which ensures that only one matching route is loaded at a time. But this no longer exists in v6. We use the Routes component to replace the Switch. Note that we still need to import BrowserRouter to wrap our application, just as we did in v5.

In v5, we do this:

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

function App() {
    return (
        <BrowserRouter>
            <div className="App">
                <Switch>
                    {" "}
                    {/* Route is defined here */}
                </Switch>
            </div>
        </BrowserRouter>
    );
}
export default App

But in v6, we will do this

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

function App() {
    return (
        <BrowserRouter>
            <div className="App">
                <Routes>
                    {" "}
                    {/* Switch Will be changed to Routes */}
                    {/* Route is defined here */}
                </Routes>
            </div>
        </BrowserRouter>
    );
}

export default App

Route component usage update

Although the Route component still retains a place in v6, we define its use differently than we did in v5. We will no longer place the components we want to render in any way in v5, but uniformly pass them as the value of elementprop.

No exact configuration

In v5, if exact is not added as props of the Route component, if the URL starts with the path keyword, the path will match, because the matching process is from top to bottom. However, in v6, we will no longer need this exact configuration because the path pattern matching algorithm has changed and is now more enhanced.

In v5, we did this:

<Switch>
   {/* Three Route component usage definitions */}
   <Route path="/signup" component={Product} />
   {/* or */}
   {/* This method allows us to pass props to the rendered component */}
   <Route path="/games">
       <Product id={2} />
   </Route>
   {/* Or through the render function */}
   <Route path="/games" render={(props) => <Product {...props} />} />
</Switch>

In v6,

<Routes>
   {" "}
   <Route path="/games" element={<Product />} />
   {/* Rendering component with props */}
   <Route path="/movies" element={<Product id={200} category="shirt" />} />
</Routes>

Links and NavLinks

Link and NavLink components can still run in V6. The use of link component remains the same as that in v5, but when using NavLink component, activeClassName and activeStyle prop are deleted. In v5, activeClassNameprop is used to automatically apply some CSS classes to links after link activation, and activeStyle allows us to add internal styles to links when links are activated.

But in v6, we can now use a function to get information about the link activity status. The argument to this function is an object isActive with properties. This property is true when the link is active and false when it is inactive. The value of isActive allows us to use conditional expressions to indicate the activity style or class name.

In v5, we did this:

import {NavLink} from "react-router-dom"

{/* ... */}
<NavLink
   to="/product"
   style={{ color: "#689" }}
   activeStyle={{ color: "#3072c9" }}
   className="nav_link"
   activeClassName="active"
>
   Products
</NavLink>

But in v6, we will do this:

<NavLink
   to="/product"
   style={({ isActive }) => ({ color: isActive ? "#3072c9" : "#689" })}
   className={({ isActive }) => `link${isActive ? " active" : ""}`}
>
   Product
</NavLink>

Navigate replaces Redirect

In v5, we use the Redirect component to bring one page to another, but it is no longer exported from the react router DOM in v6. It has been replaced by the Navigate component.

In v5, we did this:

<Route path="/faq">
   <Redirect to="/about" />
</Route>
<Route path="/about" component={About} />

But in v6, we will do this:

<Route path="/games" element={<Navigate to="/about" />} />;
<Route path="/games" element={<About />} />;

It should be noted that if we only add components as in the code snippet above navigation, it will only push the navigation to the path to the navigation stack. However, if we plan to replace the current page with a new page, we will add the replace attribute to the navigation component, as shown below:
<Route path="/games" element={<Navigate replace to="/about" />} />;

Nested Route

As the name suggests, a nested route is a route placed in another route. They are used to present more specific information in subcomponents. In v6, we place nested routes as child routes of the parent route. Then we introduce the Outlet component, which is exported from the react router DOM in the rendering component to specify where we want the nested information to be displayed. The Outlet component is not required, but it makes the code clearer.
In v5, we did this:

import { useRouteMatch } from "react-router-dom";
function App() {
   return (
       <BrowserRouter>
           <Switch>
               <Route exact path="/about" component={About} />
               <Route path="/product" component={Product} />
           </Switch>
       </BrowserRouter>
   );
}

function Product() {
   let match = useRouteMatch();
   return (
       <div>
           <Switch>
               {/* match.path Returns the path specified in the parent route. In this case, it is "/ product"“ */}
               <Route path={`${match.path}`}>
                   <AllProducts />
               </Route>
               {/* Match / product/:id */}
               <Route path={`${match.path}/:id`}>
                   <ProductDetail />
               </Route>
           </Switch>

       </div>
   );
}

In v6, we do this:

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

function App() {
   return (
       <Routes>
           <Route path="/about" element={<About />} />
           <Route path="/product" element={<Product />}>
               {/* Here, the path of the nested route is relative to the path of the parent route. */}
               {/* Here it becomes "/ product / */}
               <Route path="/" element={<AllProducts />} />
               {/* Here it becomes "/ product/:id" */}
               <Route path="/:id" element={<ProductDetail />} />

           </Route>
       </Routes>
   );
}

function Product() {
   return (
       <Container>
           <>
               <div>Product</div>
               {/* Other contents of the parent component */}
           </>
           {/* This is where nested information begins */}
           <Outlet />
       </Container>
   );
}

Programmed navigation

Programmatic navigation occurs when the user is redirected due to events on the path (such as clicking a button, API request completion, etc.). In v5, we can use the useHistory hook to perform the following operations:

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

function Product() {
   const history = useHistory();

   const handleClick = () => {
       //This pushes the new route to the top of the navigation stack
       history.push("/new-route");

       //This replaces the current route with the new route in the navigation stack
       history.replace("/new-route");
   };

   return (
       <div>
           <button>Click me to redirect to the new route</button>
       </div>
   );
}

But in v6, useHistoryhook is replaced with useNavigatehook, and we use it in different ways.

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

function Product() {
   const navigate = useNavigate();

   const handleClick = () => {
       //This pushes the new route to the top of the navigation stack
       navigate("/new-route");

       //This replaces the current route with the new route in the navigation stack
       navigate("/new-route", { replace: true });
   };

   return (
       <div>
           <button>Click me to redirect to the new route</button>
       </div>
   );
}

One cool thing is that we can move forward and backward on the navigation stack at will. By using a positive number as the above parameter navigate(), the route moves forward by this number of steps. Negative numbers do the same thing backwards

// Goes forward
navigate(1)
// Goes forward twice
navigate(2)
// Goes backward
navigate(-1)
// Goes backward three times
navigate(-3)

Remove Prompt component

Prompt if there are unsaved changes, the components in v5 can prevent accidental leaving the page. But the react router team did not include it in v6, and there was no alternative. Therefore, if you need this function, you can implement it manually or return to v5.

Except that Prompt is not included, both useBlocker and usePrompt do not work in the current version (v6). Although the react router team said in the official document that they are currently trying to add it back to v6, it is not aimed at 6 The first stable version of X.

generalization

Let's highlight the changes we have experienced.

  • Replace the Switch component with the Routes component.
  • How to place changes to the render components of Route.
  • There is no exact in the route.
  • activeClassName and activeStyle no longer exist in the NavLink component
  • We can access the isActive state of the NavLink component through the function callback.
  • The Redirect component has been replaced with the Navigate component.
  • A more fashionable way to implement nested routing.
  • No Prompt component

In short, if you are not ready to switch from v5 or any other version to v6, you can continue to use it to install the previous version.

npm install react-router-dom@[VERSION_NUMBER]

However, you will miss some good things that come with v6, including but not limited to:

  • Enhanced path pattern matching algorithm.
  • According to Bundlephobia, the volume size is reduced by 60%
  • I believe we can successfully Switch to react router V6 and stop using the Switch component (pun intended) 😌.

    Better coding experience 🙌.

Topics: react-router