I am always excited when there is a new release of any of my favourite libraries/frameworks/languages, At about 6 pm yesterday while scrolling through twitter I saw that a new version of react-router was released so I went to look it up and the react-router team added some really nice new API's and functionality.
The react-router team added to the ongoing React hooks buzz by releasing some hooks API in its version 5.1 with the release of the useParams
, useLocation
, useHistory
and useRouteMatch
hooks. These hooks give us new ways to manage the router's state. Apart from the hooks added to the v5.1 there is now support for forwardRef
in the <Link>
and they reintroduced the ability to pass functions in the to
prop of the <Link>
and <NavLink>
.
I will be walking through how those hooks work and how do they change the way we write our routes.
useParams
This hook gives us access to the params of that particular route. params are parameters whose values are set dynamically in a URL. Usually, the way we access the params in previous versions of react-router was through the match props passed to the component.
// <= V5.0
import { BrowserRouter as Router, Route, Switch, Link } from "react-router-dom";
const Portfolio = props => {
const { match } = props;
let {id} = match.params;
return (
<div>
Portfolio component
<p>Url params: {id}</p>
</div>
);
};
function App() {
return (
<div className="App">
<Router>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/contact">Contact</Link>
</li>
<li>
<Link to="/portfolio/6">Portfolio</Link>
</li>
</ul>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/portfolio/:id" component={Portfolio} />
<Route path="/contact" component={Contact} />
</Switch>
</Router>
</div>
);
}
Above is the approach we use to access the URL params in previous versions of react-router. But with the introduction of useParams hook, all users can get access to the params from the hook.
// > V5.1
import { useParams} from "react-router";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
const Portfolio = () => {
let { id } = useParams();
return (
<div>
Portfolio component
<p>Topic: {id}</p>
</div>
);
};
useLocation
This is another hook released in v5.1, if you use react-router a lot I assume that you have used the location object before either to get the pathname
property or the state property. I usually pass state through the react-router Link
so I think I will be refactoring my components to use the useLocation hook, this will probably be my first react hook in production 👀(I know I am late to the party).
Note: Passing state through react-router's <Link>
isn't a new feature, it has been there since I started using React.
// > V5.1
import { useLocation} from "react-router";
const Settings = () => {
let location = useLocation();
console.log(location);
return <div>settings component</div>;
};
function App() {
return (
<div className="App">
<Router>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link
to={{
pathname: "/settings",
state: {
fromNavBar: true
}
}}
>
Settings
</Link>
</li>
</ul>
<Switch>
<Route exact path="/" component={Home} />
//
<Route path="/settings" component={Settings} />
</Switch>
</Router>
</div>
);
}
// console
// {
// "pathname": "/settings",
// "state": {
// "fromNavBar": true
// },
// "search": "",
// "hash": "",
// "key": "x8vmq3"
// }
The useLocation
hook returns the location object which contains the pathname
, search
, hash
, key
and the state
properties of the current location.
useHistory
The useHistory
gives us access to the history
object which helps us programmatically navigate or change routes.
// > V5.1
import { useHistory } from "react-router-dom";
export const Profile = () => {
let history = useHistory();
return (
<div>
<button onClick={() => history.goBack()}>Back</button>
<button onClick={() => history.push("/")}>Home</button>
<section>
<p>profile page</p>
</section>
</div>
);
};
The history object also returns the location object as one of its properties but it is advised to not to use the location returned by it because history is mutable, so use the useLocation
hook for that.
useRouteMatch
This is the final hook added to this release, useRouteMatch
gives you access to the match
property without rendering a <Route>
component. It matches the URL just like a Route would and it accepts an exact
, strict
, path
and sensitive
options just like a <Route>
. Before V5.1 the ways to access the match
object are through:
- Route component as this.props.match
- Route render as ({ match }) => ()
- Route children as ({ match }) => ()
- withRouter as this.props.match
- matchPath as the return value
// <= V5.0
function App() {
return (
<div className="App">
<Router>
<Route
path="'/Movies/:id/'"
strict
sensitive
render={({ match }) => {
return match && <Movies match={match} />;
}}
/>
</Router>
</div>
);
}
// > V5.1
import { useRouteMatch } from "react-router";
function App() {
let match = useRouteMatch({
path: "/Movies/:id/",
strict: true,
sensitive: true
});
return (
<div>
{match && <Movies match={match} />}
</div>
);
}
useRouteMatch
gives us a new way to access the match object and if you have an <Route>
that is not inside a Switch
it makes sense to use useRouteMatch
. I mean it is hooks szn!!!
Conclusion
I really love these hooks added to the react-router API, they give us the ability to compose router state which opens new possibilities in term of building application. Excited to see what other new features and APIs are introduced in future releases also the react-router team is hoping to release version 6 early next year.
Top comments (12)
Hi Nero,
I'm just learning reactJS and I'm having a problem with app I'm working on.
It is supposed to be an online store. I've a product object use to store data about the various products for sale.
The challenge I'm having is how to pass this object in my route statement to the component that will display this object as a kind of catalog.
Currently, I've the following line in my router block:
where {Product} is the component.
I'll really appreciate your help. Thanks.
There is a bug at the example for useParams in V5.0
the 4th line:
let id = match.params;
It should be :
let {id} = match.params;
thanks for pointing that out
Thank you for this post !
I will try these soon :D
Nice post!
In your second code block you imported useHistory but then used useParam.
Fixed that.
Thanks Justus
Hi nero, I was wondering how to make a protected route using react-router hooks ?? thanks
Bro, you are a life saver!! thanks a lot!! I didnt kno y location wasnt working for me until I found your post, hooks have got me forgetting how to walk the walk
Very nice! I've been waiting for this
Nice to see, but I do not understand the last hook, can you introduce me more?
Maybe a different usecase of useRouteMatch might help you understand. Checkout this short tutorial link
This incredible stuffs.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.