How to create a simple React router hook using React's built-in functionality (and React's own code)
Published on Aug. 22, 2023, 12:12 p.m.
If you use ReactRouter you might have noticed they recently added a number of useful hooks.But let’s see if we can make it even simpler by wrapping them up into a single useRouter hook.In this recipe we show how easy it is to compose multiple hooks.It makes a lot of sense using only the hook you need can minimize unnecessary re-renders.That said, sometimes you want a simpler developer experience .
import { useMemo } from "react";
import {
useParams,
useLocation,
useHistory,
useRouteMatch,
} from "react-router-dom";
import queryString from "query-string";
// Usage
function MyComponent() {
// Get the router object
const router = useRouter();
// Get value from query string (?postId=123) or route param (/:postId)
console.log(router.query.postId);
// Get current pathname
console.log(router.pathname);
// Navigate with router.push()
return <button onClick={(e) => router.push("/about")}>About</button>;
}
// Hook
export function useRouter() {
const params = useParams();
const location = useLocation();
const history = useHistory();
const match = useRouteMatch();
// Return our custom router object
// Memoize so that a new object is only returned if something changes
return useMemo(() => {
return {
// For convenience add push(), replace(), pathname at top level
push: history.push,
replace: history.replace,
pathname: location.pathname,
// Merge params and parsed query string into single "query" object
// so that they can be used interchangeably.
// Example: /:topic?sort=popular -> { topic: "react", sort: "popular" }
query: {
...queryString.parse(location.search), // Convert string to object
...params,
},
// Include match, location, history objects so we have
// access to extra React Router functionality if needed.
match,
location,
history,
};
}, [params, match, location, history]);
}