DEV Community

Cover image for Hooks Introduced in React-Router v5.1
Nero Adaware
Nero Adaware

Posted on • Updated on

Hooks Introduced in React-Router v5.1

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>
    );
}
Enter fullscreen mode Exit fullscreen mode

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>
    );
};


Enter fullscreen mode Exit fullscreen mode

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"
// }
Enter fullscreen mode Exit fullscreen mode

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>
    );
};
Enter fullscreen mode Exit fullscreen mode

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>
    );
}
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (12)

Collapse
ezzbee profile image
Ezzbee

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.

Collapse
ageofcode profile image
ageofcode

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;

Collapse
finallynero profile image
Nero Adaware Author

thanks for pointing that out

Collapse
keziahmoselle profile image
Keziah

Thank you for this post !
I will try these soon :D

Collapse
justusburger profile image
Justus Burger

Nice post!

In your second code block you imported useHistory but then used useParam.

Collapse
finallynero profile image
Nero Adaware Author

Fixed that.
Thanks Justus

Collapse
bllyanos profile image
Billy Editiano Saputra

Hi nero, I was wondering how to make a protected route using react-router hooks ?? thanks

Collapse
najdi123 profile image
Ali Najdi

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

Collapse
holtmansfield profile image
Holt Mansfield

Very nice! I've been waiting for this

Collapse
starinsun profile image
starinsun

Nice to see, but I do not understand the last hook, can you introduce me more?

Collapse
finallynero profile image
Comment marked as low quality/non-constructive by the community. View Code of Conduct
Nero Adaware Author

Maybe a different usecase of useRouteMatch might help you understand. Checkout this short tutorial link

Collapse
developerruhul profile image
Developer Ruhul

This incredible stuffs.