This article is the continuation of React-router-v6 what changed and Upgrading guide, React-router-v6 what changed and Upgrading guide - part-2 articles. Please visit the previous article if you are in the beginning stage of migrating React Router v.5 to v.6
In the last article we end up with Nested Route, let's continue with some extra points with Nested Route.
Routes are Relative
According to v.5, we’ll use nested routes as follows,
App.js
App(){
return{
<Routes>
<Route path=’/component1’ element={<Component1 />}/>
</Routes>
}}
Component1.js
Const Component1 = () => {
return(
<container>
<Routes>
<Route path=’/component1/component2’ element={<component2/>} />
</Routes>
</container>
)}
The above nested route method will work fine in v.5, but in v.6 this won't work, in v.6 the logic and syntax we needed for nested routes is changed, it's actually changed for the better.
As we already mentioned in part 1 article, we can add “/*” to React Router and it should match the route for the start of the path instead of the full path.
Eg: <Route path=’/products/*’ element={<Products/>} />
So, according to the above example code, route will render component1, but it wont render component2 in v.6.
To make component2 render, first we have to embrace this new syntax “/*” in the parent route.
App.js
App(){
return{
<Routes>
<Route path=’/component1/*’ element={<Component1 />}/>
</Routes>
}}
Above code component1 route will become active if the path starts with /component1.
In component1 we have used nested routes, therefore the route path in component1 already assumes, that we have /component1 at the beginning. Hence, we have to add only the extra part, the extra elements in the path that are relevant for the route, not full path.
We don’t need to repeat full path /component1/component2 anymore.
Component1.js
Const Component1 = () => {
return(
<container>
<Routes>
<Route path=’ /component2’ element={ <component2 />} />
</Routes>
</container>
)}
This new change is not difficult to update from v.5, actually it is a good change, because we can keep our nested route path shorter, and we don’t need o repeat the entire fill path every time.
As a side note, if we used link,
Component1.js
Const Component1 = () => {
return (
<container>
<Routes>
<Link to=’component2’> component2 </Link>
<Route path=’ /component2’ element={ <component2 />} />
</Routes>
</container>
)
}
As we have already seen, in v.5 we need to provide full path in to-props of Link, but in v.6, since this Link exist inside of the nested route component, to-props value is relative as well.
Therefore, Links and Routes are Relative, if they are loaded inside of nested route component, because that route is already loaded because of another route.
Outlet Component
We had seen above, how to do the proper nested routes in v.6. We can even improve the code by doing this nested route in app.js component.
App.js
App(){
return{
<Routes>
<Route path=’/component1/*’ element={ <Component1 />}>
<Route path=’ /component2’ element={ <component2 />} /> </Route>
</Routes>
}
}
The above code look very easy to track the route, also we can define all the Routes in a single place.
But, if we use this pattern of route define, we have to tell react router where this nested content should be inserted into the DOM. Because it was clear when we had the route definition in the nested component, now we moved that route to app.js, react router not have clear understanding where exactly the nested route should be added or render.
For this, react router v.6 introduced another new component called Outlet, which we can import from react-router-dom package.
Import {Outlet} from ‘react-router-dom’;
Const component1 = () => {
Return (
<h1> Component1 </h1>
<Outlet/>
)
}
The above simple outlet definition, telling react router, where exactly the nested route content should be inserted or render.
This outlet approach gives us the easy way, all your routes defined in one central place.
useNavigate Hook
With react router v.5, we could navigate the path by using the useHistory hook like follows,
import {useHistory} from ‘react-router-dom’;
const component1 = () =>{
const history = useHistory();
history.push(‘/path’);
history.replace(‘/path’);
}
In react router v.6, useHistory doesn’t exist anymore, instead we have a useNavigate hook. This useNavigate hook gives us a navigate object and function, and this navigate function can be executed to navigate somewhere else.
import { useNavigate } from ‘react-router-dom’;
const component1 = () =>{
const navigate = useNavigate ();
navigate(‘/path’);
}
This is how we can navigate programmatically, there is no push function in useNavigate. Also if we want to redirect using useNavigate, we need to pass a second argument, which is an object with some options, there we can set the replace to true, which will replace the current route with the new one, mean which will redirect instead of pushing the new route onto the navigation stack.
navigate(‘/path’, {replace: true});
Also, besides passing a path in navigate, we can also pass the numbers.
Navigate(-1); // to go back to the previous page.
Navigate(-2); // go to the page before the previous page.
Navigate(1); // go to forward page.
Forward and backward navigation is also possible with this navigate function.
Prompt component v.5
This prompt component is provided by react router v.5, this component is mainly used for preventing accidentally leaving the page, without saving the current work done.
Sad news, in react router v.6 this component does not exist anymore, also there is no alternative component for this prompt component. We have to implement our own workaround to achieve this prompt functionality.
Maybe for this reason, you might want to stick to v.5 if this is a super important feature of your application and not willing to come up with own logic on how to prevent the page navigation without saving the current work.
We can expect this prompt component will probably come back in the future in react router v.6.
I hope the series of these articles are very helpful for you to learn about the react router v.6, also the migration steps.