diff --git a/lib/router/index.js b/lib/router/index.js
index 5507e8d6..e9c31c5e 100644
--- a/lib/router/index.js
+++ b/lib/router/index.js
@@ -15,7 +15,7 @@ const SingletonRouter = {
// Create public properties and methods of the router in the SingletonRouter
const urlPropertyFields = ['pathname', 'route', 'query', 'asPath']
-const propertyFields = ['components']
+const propertyFields = ['components', 'events']
const routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']
const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']
diff --git a/readme.md b/readme.md
index 6ff3d58c..6f65079b 100644
--- a/readme.md
+++ b/readme.md
@@ -544,37 +544,39 @@ This uses the same exact parameters as in the `` component.
You can also listen to different events happening inside the Router.
Here's a list of supported events:
-- `onRouteChangeStart(url)` - Fires when a route starts to change
-- `onRouteChangeComplete(url)` - Fires when a route changed completely
-- `onRouteChangeError(err, url)` - Fires when there's an error when changing routes
-- `onBeforeHistoryChange(url)` - Fires just before changing the browser's history
-- `onHashChangeStart(url)` - Fires when the hash will change but not the page
-- `onHashChangeComplete(url)` - Fires when the hash has changed but not the page
+- `routeChangeStart(url)` - Fires when a route starts to change
+- `routeChangeComplete(url)` - Fires when a route changed completely
+- `routeChangeError(err, url)` - Fires when there's an error when changing routes
+- `beforeHistoryChange(url)` - Fires just before changing the browser's history
+- `hashChangeStart(url)` - Fires when the hash will change but not the page
+- `hashChangeComplete(url)` - Fires when the hash has changed but not the page
> Here `url` is the URL shown in the browser. If you call `Router.push(url, as)` (or similar), then the value of `url` will be `as`.
-Here's how to properly listen to the router event `onRouteChangeStart`:
+Here's how to properly listen to the router event `routeChangeStart`:
```js
-Router.onRouteChangeStart = url => {
+const handleRouteChange = url => {
console.log('App is changing to: ', url)
}
+
+Router.events.on('routeChangeStart', handleRouteChange)
```
-If you no longer want to listen to that event, you can simply unset the event listener like this:
+If you no longer want to listen to that event, you can unsubscribe with the `off` method:
```js
-Router.onRouteChangeStart = null
+Router.events.off('routeChangeStart', handleRouteChange)
```
If a route load is cancelled (for example by clicking two links rapidly in succession), `routeChangeError` will fire. The passed `err` will contain a `cancelled` property set to `true`.
```js
-Router.onRouteChangeError = (err, url) => {
+Router.events.on('routeChangeError', (err, url) => {
if (err.cancelled) {
console.log(`Route to ${url} was cancelled!`)
}
-}
+})
```
##### Shallow Routing
diff --git a/test/integration/static/test/index.test.js b/test/integration/static/test/index.test.js
index 3fea134b..75387388 100644
--- a/test/integration/static/test/index.test.js
+++ b/test/integration/static/test/index.test.js
@@ -40,9 +40,11 @@ describe('Static Export', () => {
renderViaHTTP(devContext.port, '/dynamic/one')
])
})
- afterAll(() => {
- stopApp(context.server)
- killApp(devContext.server)
+ afterAll(async () => {
+ await Promise.all([
+ stopApp(context.server),
+ killApp(devContext.server)
+ ])
})
ssr(context)
diff --git a/test/integration/with-router/components/header-nav.js b/test/integration/with-router/components/header-nav.js
new file mode 100644
index 00000000..d1440336
--- /dev/null
+++ b/test/integration/with-router/components/header-nav.js
@@ -0,0 +1,52 @@
+import * as React from 'react'
+import { withRouter } from 'next/router'
+import Link from 'next/link'
+
+const pages = {
+ '/a': 'Foo',
+ '/b': 'Bar'
+}
+
+class HeaderNav extends React.Component {
+ constructor ({ router }) {
+ super()
+
+ this.state = {
+ activeURL: router.asPath
+ }
+
+ this.handleRouteChange = this.handleRouteChange.bind(this)
+ }
+
+ componentDidMount () {
+ this.props.router.events.on('routeChangeComplete', this.handleRouteChange)
+ }
+
+ componentWillUnmount () {
+ this.props.router.events.off('routeChangeComplete', this.handleRouteChange)
+ }
+
+ handleRouteChange (url) {
+ this.setState({
+ activeURL: url
+ })
+ }
+
+ render () {
+ return (
+
+ )
+ }
+}
+
+export default withRouter(HeaderNav)
diff --git a/test/integration/with-router/pages/_app.js b/test/integration/with-router/pages/_app.js
new file mode 100644
index 00000000..a8e4213b
--- /dev/null
+++ b/test/integration/with-router/pages/_app.js
@@ -0,0 +1,25 @@
+import App, { Container } from 'next/app'
+import React from 'react'
+import HeaderNav from '../components/header-nav'
+
+export default class MyApp extends App {
+ static async getInitialProps ({ Component, router, ctx }) {
+ let pageProps = {}
+
+ if (Component.getInitialProps) {
+ pageProps = await Component.getInitialProps(ctx)
+ }
+
+ return {pageProps}
+ }
+
+ render () {
+ const { Component, pageProps } = this.props
+ return (
+
Page B!
+