mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Add Router method to execute custom logic before popstate events (#3956)
* Add router method to inject code before popstate events * Default _beforePopState, return true * Fix link in README * Re-order `if` statements per feedback
This commit is contained in:
parent
a785f303f4
commit
085b2f806a
|
@ -15,8 +15,8 @@ const SingletonRouter = {
|
|||
|
||||
// Create public properties and methods of the router in the SingletonRouter
|
||||
const propertyFields = ['components', 'pathname', 'route', 'query', 'asPath']
|
||||
const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch']
|
||||
const routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError']
|
||||
const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']
|
||||
|
||||
propertyFields.forEach((field) => {
|
||||
// Here we need to use Object.defineProperty because, we need to return
|
||||
|
|
|
@ -40,6 +40,7 @@ export default class Router {
|
|||
this.subscriptions = new Set()
|
||||
this.componentLoadCancel = null
|
||||
this.onPopState = this.onPopState.bind(this)
|
||||
this._beforePopState = () => true
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
// in order for `e.state` to work on the `onpopstate` event
|
||||
|
@ -66,6 +67,12 @@ export default class Router {
|
|||
return
|
||||
}
|
||||
|
||||
// If the downstream application returns falsy, return.
|
||||
// They will then be responsible for handling the event.
|
||||
if (!this._beforePopState(e.state)) {
|
||||
return
|
||||
}
|
||||
|
||||
const { url, as, options } = e.state
|
||||
this.replace(url, as, options)
|
||||
}
|
||||
|
@ -265,6 +272,10 @@ export default class Router {
|
|||
this.notify(data)
|
||||
}
|
||||
|
||||
beforePopState (cb) {
|
||||
this._beforePopState = cb
|
||||
}
|
||||
|
||||
onlyAHashChange (as) {
|
||||
if (!this.asPath) return false
|
||||
const [ oldUrlNoHash, oldHash ] = this.asPath.split('#')
|
||||
|
|
33
readme.md
33
readme.md
|
@ -458,6 +458,31 @@ export default () =>
|
|||
</div>
|
||||
```
|
||||
|
||||
#### Intercepting `popstate`
|
||||
|
||||
In some cases (for example, if using a [custom router](#custom-server-and-routing)), you may wish
|
||||
to listen to `popstate` and react before the router acts on it.
|
||||
For example, you could use this to manipulate the request, or force an SSR refresh.
|
||||
|
||||
```jsx
|
||||
import Router from 'next/router'
|
||||
|
||||
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
|
||||
});
|
||||
```
|
||||
|
||||
If you return a falsy value from `beforePopState`, `Router` will not handle `popstate`;
|
||||
you'll be responsible for handling it, in that case.
|
||||
See [Disabling File-System Routing](#disabling-file-system-routing).
|
||||
|
||||
Above `Router` object comes with the following API:
|
||||
|
||||
- `route` - `String` of the current route
|
||||
|
@ -466,6 +491,7 @@ Above `Router` object comes with the following API:
|
|||
- `asPath` - `String` of the actual path (including the query) shows in the browser
|
||||
- `push(url, as=url)` - performs a `pushState` call with the given url
|
||||
- `replace(url, as=url)` - performs a `replaceState` call with the given url
|
||||
- `beforePopState(cb=function)` - intercept popstate before router processes the event.
|
||||
|
||||
The second `as` parameter for `push` and `replace` is an optional _decoration_ of the URL. Useful if you configured custom routes on the server.
|
||||
|
||||
|
@ -753,6 +779,13 @@ module.exports = {
|
|||
}
|
||||
```
|
||||
|
||||
Note that `useFileSystemPublicRoutes` simply disables filename routes from SSR; client-side routing
|
||||
may still access those paths. If using this option, you should guard against navigation to routes
|
||||
you do not want programmatically.
|
||||
|
||||
You may also wish to configure the client-side Router to disallow client-side redirects to filename
|
||||
routes; please refer to [Intercepting `popstate`](#intercepting-popstate).
|
||||
|
||||
#### Dynamic assetPrefix
|
||||
|
||||
Sometimes we need to set the `assetPrefix` dynamically. This is useful when changing the `assetPrefix` based on incoming requests.
|
||||
|
|
Loading…
Reference in a new issue