React router 6 comes with first class suspense support, many new features and many enhancements. Let's looks at those case by case.
1. Welcome new Routes component
In this version, Switch
component is replaced by Routes
component, to support the branch new feature named relative routing.
function App() {
return (
<BrowserRouter>
<Routes> // Replace Switch with Routes
<Route path="/Home">
<Home />
</Route>
<Route path="/user">
<Users />
</Route>
</Routes>
</BrowserRouter>
)
}
2. Truely Relative Routes
When we write nested route, here after we don't need to specify full complete route path by combining the current route's path + new route slug.
// In v5 we used to do like this
function App() {
return (
<BrowserRouter>
<Route path="/user">
<Users />
</Route>
</BrowserRouter>
)
}
function Users() {
let match = useRouteMatch();
return (
<div>
<nav>
<Link to={`${match.url}/me`}>My Profile</Link>
</nav>
<Switch>
<Route path={`${match.path}/me`}>
<OwnUserProfile />
</Route>
<Route path={`${match.path}/:id`}>
<UserProfile />
</Route>
</Switch>
</div>
);
}
// v6
function App() {
return (
<BrowserRouter>
<Route path="/user/*">
<Users />
</Route>
</BrowserRouter>
)
}
function Users() {
let match = useRouteMatch();
return (
<div>
<nav>
<Link to={`me`}>My Profile</Link>
</nav>
// We used <Routes> instead of <Switch>, which is new replacement.
<Routes>
<Route path={`me`}>
<OwnUserProfile />
</Route>
<Route path={`:id`}>
<UserProfile />
</Route>
</Routes>
</div>
);
}
Did you observed the <Route path={
me}>
, this is the huge win, now we no longer need to construct the full path, which tedious.
Also did you noticed *
here <Route path="/user/*">
. *
hints the React Router that this Routes contains Sub-routes. With that followings are all valid path pattern
/groups
/groups/admin
/users/:id
/users/:id/messages
/files/*
/files/:id/*
/files-*
3. More powerful Navigation
Goodbye History API
and welcome Navigation API
. Yes, In V6, we have new apis and hooks for better navigation.
import { useNavigate } from "react-router-dom";
function App() {
let navigate = useNavigate();
function handleClick() {
navigate("/home");
}
return (
<div>
<button onClick={handleClick}>go home</button>
</div>
);
}
Also we can leverage the same relative routing advantages in navigate
apis too
import { Routes, Route, useNavigate } from "react-router-dom";
function App() {
let navigate = useNavigate();
function handleClick() {
navigate("/home");
}
return (
<Routes>
<Route element={<Home />} path="/home">
</Routes>
);
}
function Home() {
let navigate = useNavigate();
const onClick = () => {
// this will navigate to the /home/dashboard
navigate("dashboard", { state: { report: "pivot" }, replace: true })
};
return (
<button onClick={onClick}>
Dashboard
</button>
);
}
We have new ways of doing history.goBack
, history.goForward
with new navigation
import { useNavigate } from "react-router-dom";
function App() {
const navigate = useNavigate();
return (
<>
<button onClick={() => navigate(-2)}>Go 2 pages back</button>
<button onClick={() => navigate(-1)}>Go back</button>
<button onClick={() => navigate(1)}>Go forward</button>
<button onClick={() => navigate(2)}>Go 2 pages forward</button>
</>
);
}
With a new navigation, Redirect
component is replaced with new Navigate
component.
import { Navigate } from "react-router-dom";
function App() {
return <Navigate to="/home" replace state={state} />;
}
4. New Outlet component
To bring all the routes to one place and give nicer way to nest them, v6 has brought back the Outlet
component. <Route children />
way of defining the routes provides us a way to cleanly specify the nested routes of a module or sub modules of our app.
// This is a React Router v6 app
import { BrowserRouter, Routes, Route, Link, Outlet } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="users" element={<Users />}>
<Route path="me" element={<OwnUserProfile />} />
<Route path=":id" element={<UserProfile />} />
</Route>
</Routes>
</BrowserRouter>
);
}
function Users() {
return (
<div>
<nav>
<Link to="me">My Profile</Link>
</nav>
// Children of users route will be rendered here when visiting /users/me or /users/id
<Outlet />
</div>
);
}
We have nested Route
inside Route
, this is cool way of defining all the child routes of a component in one place and we render them using <Outlet />
component.
5. New useRoutes hook
With this hook we can create our routes definition using json object instead with components.
function App() {
let element = useRoutes([
// These are the same as the props you provide to <Route>
{ path: "/", element: <Home /> },
{ path: "dashboard", element: <Dashboard /> },
{
path: "invoices",
element: <Invoices />,
// Nested routes use a children property, which is also
// the same as <Route>
children: [
{ path: ":id", element: <Invoice /> },
{ path: "sent", element: <SentInvoices /> }
]
},
// Not found routes work as you'd expect
{ path: "*", element: <NotFound /> }
]);
// The returned element will render the entire element
// hierarchy with all the appropriate context it needs
return element;
}
6. NavLink components className and style props now accepts function
activeClassNamve
and activeStyle
props are removed in favour of this feature.
<NavLink
to="/messages"
className={({ isActive }) => "nav-link" + (isActive ? " activated" : "")}
>
Messages
</NavLink>
<NavLink
to="/messages"
style={({ isActive }) => ({ color: isActive ? 'green' : 'blue })}
>
Messages
</NavLink>
React Router v6 brings more enhancements along with these main features, for more info refer here