There are two ways to access router
within components.
useRouter()
(recommended)withRouter()
useRouter
import { useRouter } from "blitz"
function Thing({ href }) {
const router = useRouter()
return (
<div
style={{
color: router.pathname === href ? "red" : "black",
}}
/>
)
}
export default Thing
useRouter
is a React Hook, meaning it cannot be used with classes. You can either use withRouter or wrap your class in a function component.
withRouter
import { withRouter } from "blitz"
function Page({ router }) {
return <p>{router.pathname}</p>
}
export default withRouter(Page)
router
objectHere's the definition of the router
object returned by useRouter
and
withRouter
:
pathname
: String
- Current route. That is the path of the page in
/pages
query
: Object
- All the query string parameters from the current
url. Parameter type is always string
.params
: Object
- All the dynamic route parameters for the current
route. Parameter types are string
or string[]
.asPath
: String
- Actual path (including the query) shown in the
browserpush()
: Make page navigationreplace()
: Make page navigation without adding to
browser historyback()
: Navigate to previous history locationreload()
: Reload the pageprefetch()
: Prefetch pages for faster client-side
transitionsevents
: Subscribe to various router eventsbeforePopState()
: For advanced routing
needsThe following router APIs can also be used via
import {Router} from 'blitz'
Handles client-side transitions, this method is useful for cases where
<Link>
is not enough.
import { Router } from "blitz"
Router.push(url, as, options)
url
- The URL to navigate to. This is usually the name of a page
as
- Optional decorator for the URL that will be shown in the browser.
Defaults to url
options
- Optional object with the following configuration options:shallow
: Update the path of the current page
without rerunning getStaticProps
or
getServerSideProps
. Defaults to false
You don't need to use
Router
for external URLs, window.location is better suited for those cases.
Navigating to pages/about.js
, which is a predefined route:
import { Router } from "blitz"
function Page() {
return <span onClick={() => Router.push("/about")}>Click me</span>
}
Navigating pages/post/[pid].js
, which is a dynamic route:
import { Router } from "blitz"
function Page() {
return <span onClick={() => Router.push("/post/abc")}>Click me</span>
}
You can use an URL object in the same way you can use it for
<Link>
. Works for both the url
and as
parameters:
import { Router } from "blitz"
const handler = () => {
Router.push({
pathname: "/about",
query: { name: "Vercel" },
})
}
function ReadMore() {
return (
<div>
Click <span onClick={handler}>here</span> to read more
</div>
)
}
export default ReadMore
Similar to the replace
prop in <Link>
, Router.replace
will
prevent adding a new URL entry into the history
stack, take a look at
the following example:
import { Router } from "blitz"
Router.replace("/home")
The API for Router.replace
is exactly the same as that used for
Router.push
.
Navigate back in history. Equivalent to clicking the browser’s back
button. It executes window.history.back()
.
import { Router } from "blitz"
Router.back()
Reload the current URL. Equivalent to clicking the browser’s refresh
button. It executes window.location.reload()
.
import { Router } from "blitz"
Router.reload()
Prefetch pages for faster client-side transitions. This method is only
useful for navigations without <Link>
because it takes care of
prefetching pages automatically.
This is a production only feature. Next.js doesn't prefetch pages on development.
import { Router } from "blitz"
Router.prefetch(url, as)
url
- The path to a page
inside the pages
directoryas
- Optional decorator for url
, used to prefetch
dynamic routes. Defaults to url
Let's say you have a login page, and after a login, you redirect the user to the dashboard. For that case, we can prefetch the dashboard to make a faster transition, like in the following example:
import { Router } from "blitz"
export default function Login() {
const handleSubmit = React.useCallback((e) => {
e.preventDefault()
fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
/* Form data */
}),
}).then((res) => {
// Do a fast client-side transition to the already prefetched dashboard page
if (res.ok) Router.push("/dashboard")
})
}, [])
React.useEffect(() => {
// Prefetch the dashboard page as the user will go there after the login
Router.prefetch("/dashboard")
}, [])
return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
<button type="submit">Login</button>
</form>
)
}
You can listen to different events happening inside the Router. Here's a list of supported events:
routeChangeStart(url)
- Fires when a route starts to changerouteChangeComplete(url)
- Fires when a route changed completelyrouteChangeError(err, url)
- Fires when there's an error when changing
routes, or a route load is cancellederr.cancelled
- Indicates if the navigation was cancelledbeforeHistoryChange(url)
- Fires right before changing the browser's
historyhashChangeStart(url)
- Fires when the hash will change but not the
pagehashChangeComplete(url)
- Fires when the hash has changed but not the
pageHere
url
is the URL shown in the browser. If you callRouter.push(url, as)
(or similar), then the value ofurl
will beas
.
For example, to listen to the router event routeChangeStart
, do the
following:
import { Router } from "blitz"
const handleRouteChange = (url) => {
console.log("App is changing to: ", url)
}
Router.events.on("routeChangeStart", handleRouteChange)
If you no longer want to listen to the event, unsubscribe with the off
method:
import { Router } from "blitz"
Router.events.off("routeChangeStart", handleRouteChange)
If a route load is cancelled (for example, by clicking two links rapidly
in succession), routeChangeError
will fire. And the passed err
will
contain a cancelled
property set to true
, as in the following example:
import { Router } from "blitz"
Router.events.on("routeChangeError", (err, url) => {
if (err.cancelled) {
console.log(`Route to ${url} was cancelled!`)
}
})
Router events should be registered when a component mounts (useEffect or componentDidMount / componentWillUnmount) or imperatively when an event happens, as in the following example:
import { Router } from "blitz"
useEffect(() => {
const handleRouteChange = (url) => {
console.log("App is changing to: ", url)
}
Router.events.on("routeChangeStart", handleRouteChange)
return () => {
Router.events.off("routeChangeStart", handleRouteChange)
}
}, [])
In some cases (for example, if using a Custom Server), you may wish to listen to popstate and do something before the router acts on it.
You could use this to manipulate the request, or force a SSR refresh, as in the following example:
import { Router } from "blitz"
Router.beforePopState(({ url, as, options }) => {
// I only want to allow these two routes!
if (as !== "/" && as !== "/other") {
// Have SSR render bad routes as a 404.
window.location.href = as
return false
}
return true
})
Router.beforePopState(cb: () => boolean)
cb
- The function to run on incoming popstate
events. The function
receives the state of the event as an object with the following props:url
: String
- the route for the new state. This is usually the
name of a page
as
: String
- the url that will be shown in the browseroptions
: Object
- Additional options sent by
Router.pushIf the function you pass into beforePopState
returns false
, Router
will not handle popstate
and you'll be responsible for handling it, in
that case. See
Disabling file-system routing.