At the time of this writing, React Router v6 is still in alpha, but the time is about right to start playing with it and exploring whatβs to come. This guide will give you a peek at the new features/changes!
As you may know, the lead maintainers forked the React Router project to create a lightweight alternative called Reach Router in early 2018.
During this time, both libraries grew, however it seems that active development for Reach Router will stop, and will be merged into the upcoming React Router v6 π£
With the release coming soon, hereβs a sneak peek of whatβs coming!
This top-level component is going to be renamed. However, its functionality is mostly remaining the same.
// v5
import {
BrowserRouter,
Switch,
Route
} from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/"><Home /></Route>
<Route path="/profile"><Profile /></Route>
</Switch>
</BrowserRouter>
);
}
Just drop <Routes> in there:
// v6
import {
BrowserRouter,
Routes,
Route
} from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="profile/*" element={<Profile />} />
</Routes>
</BrowserRouter>
);
}
In v6 the <Route> component is receiving the biggest overhaul. Fortunately, these new changes will actually be making it simpler to use!
The component/render
prop will be substituted for the element
prop:
import Profile from './Profile';
// v5
<Route path=":userId" component={Profile} />
<Route
path=":userId"
render={routeProps => (
<Profile routeProps={routeProps} animate={true} />
)}
/>
// v6
<Route path=":userId" element={<Profile />} />
<Route path=":userId" element={<Profile animate={true} />} />
If you noticed, in v6 itβs much easier to pass props now. This has negated the use of the render
prop in v5.
Nested routes in v5 had to be very explicitly defined. This required including a lot of string-matching logic into these components. See <Profile>:
// v5
import {
BrowserRouter,
Switch,
Route,
Link,
useRouteMatch
} from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/profile" component={Profile} />
</Switch>
</BrowserRouter>
);
}
function Profile() {
let match = useRouteMatch();
return (
<div>
<nav>
<Link to={`${match.url}/me`}>My Profile</Link>
</nav>
<Switch>
<Route path={`${match.path}/me`}>
<MyProfile />
</Route>
<Route path={`${match.path}/:id`}>
<OthersProfile />
</Route>
</Switch>
</div>
);
}
In v6, you can remove the string-matching logic. There isnβt any need for useRouteMatch()
either! The result is pleasantly minimal:
// v6
import {
BrowserRouter,
Routes,
Route,
Link,
Outlet
} from 'react-router-dom';
// Approach #1
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="profile/*" element={<Profile/>} />
</Routes>
</BrowserRouter>
);
}
function Profile() {
return (
<div>
<nav>
<Link to="me">My Profile</Link>
</nav>
<Routes>
<Route path="me" element={<MyProfile />} />
<Route path=":id" element={<OthersProfile />} />
</Routes>
</div>
);
}
// Approach #2
// You can also define all
// <Route> in a single place
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="profile" element={<Profile />}>
<Route path=":id" element={<MyProfile />} />
<Route path="me" element={<OthersProfile />} />
</Route>
</Routes>
</BrowserRouter>
);
}
function Profile() {
return (
<div>
<nav>
<Link to="me">My Profile</Link>
</nav>
<Outlet />
</div>
)
}
Note: the <Outlet> component is used like {this.props.children}
in React Router v6. This was a very popular feature from Reach Router!
Sometimes youβll want to programmatically navigate. For example, after a user submits a form and they need to be redirected to a confirmation page. This is the useHistory
library in v5, which has been renamed to useNavigate
in v6:
// v5
import { useHistory } from 'react-router-dom';
function MyButton() {
let history = useHistory();
function handleClick() {
history.push('/home');
};
return <button onClick={handleClick}>Submit</button>;
};
Now history.push() will be replaced with navigate():
// v6
import { useNavigate } from 'react-router-dom';
function MyButton() {
let navigate = useNavigate();
function handleClick() {
navigate('/home');
};
return <button onClick={handleClick}>Submit</button>;
};
In some cases, youβll want to replace an URL in the browser history instead of pushing a new URL. This has slightly changed with v6:
// v5
history.push('/home');
history.replace('/home');
// v6
navigate('/home');
navigate('/home', {replace: true});
With all of these changes, youβd expect the bundle size to grow, but itβs actually reduced by half! The minified bundle of v5 was ~20kb, and v6 is only ~8kb.
Bundle sizes are calculated using the BundlePhobia tool.
Iβm pretty excited about the release of React Router v6. Hopefully this article has given you an idea of what to expect when it releases (which should be soon)! You can read more about React Router v6 in the latest release notes π
For a complete list of new features, see the official React Router v6 migration guide π
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the βreport an issueβ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Sign up for Infrastructure as a Newsletter.
Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Very informative!!