Next.js: Multiple event listeners per event on Router

Created on 21 May 2017  Â·  12Comments  Â·  Source: vercel/next.js

Right now, it only seems to be possible to attach one event listener to the router for each event, since this is defined as a single property on the Router singleton instance:

// Add listener
Router.onRouterEvent = myCallback;

// Remove
Router.onRouterEvent = null

I think it would be nice to be able to add an arbitrary number of event listeners in any part of the application. Suggested API:

// Add event listener
Router.on('routerEvent', callback);

// Remove event listeners
Router.off('routerEvent', callback);

Or is there already a way to do that that I missed?

Most helpful comment

I published next-router-events to make this easier for everyone.

All 12 comments

@ivome Currently you've to do it yourself. We didn't do it because there's no standard event listener API.

@arunoda Would you be open to a pull request?

I think we didn't wanted to do that. I hope @rauchg can answer this more.

It can also be implemented as an add on or external package, but I think the uses cases where you need a feature like that are quite common:

  • Loading indicator in react components + any logic that needs to listen to router events (data fetching, authentication, redirects etc.)
  • Loading indicator in multiple components

Any news on this issue? Anybody has made a custom implementation?

@acanimal not sure if that helps but I've posted a question with an example implementation on SO: https://stackoverflow.com/questions/46770364/multiple-event-listeners-in-next-js-router/46770365#46770365

sharedRouter.js (gist)

I'm using rxjs and recompose, but you could easily replace them with a singleton event emitter and regular component lifecycle hooks.

Edit: hopefully this won't sound like I'm preaching (it's just a personal preference), but a nice thing about using Observables in this scenario is that it makes it trivial to track/store the entire user navigation flow - I'm using it to catch referrers when navigating between pages (and different versions of the same page).

Edit2: Added gist

@arunoda @rauchg This really needs to be reopened. This API limitation is not obvious to a consumer and neither is a workaround. We are not able to publically publish components that rely on router events when consumers are already using the events themselves or have implemented custom workarounds.

I have a global loading indicator component that taps into onRouteChangeComplete. I also have to use the same listener to record gtag.js page load events.

Whichever code runs last works, overwriting the functionality of the other. I guess I'll have to come up with some sort of global singleton module setup.

Got a workaround working…

Install tiny-emitter:

npm install tiny-emitter

Create router-events.js:

import Emitter from 'tiny-emitter'
import Router from 'next/router'

const emitter = new Emitter()
const methodEvents = {
  onRouteChangeStart: 'routeChangeStart',
  onRouteChangeComplete: 'routeChangeComplete',
  onRouteChangeError: 'routeChangeError',
  onBeforeHistoryChange: 'beforeHistoryChange',
  onAppUpdated: 'appUpdated'
}

Object.keys(methodEvents).forEach(method => {
  Router[method] = (...args) => emitter.emit(methodEvents[method], ...args)
})

export default emitter

In components/foo.js:

import routerEvents from '../router-events.js'

const handleRouteChangeComplete1 = url => console.log(url)
const handleRouteChangeComplete2 = url => console.log(url)

routerEvents.on('routeChangeComplete', handleChangeComplete1)
routerEvents.on('routeChangeComplete', handleChangeComplete2)
routerEvents.off('routeChangeComplete', handleChangeComplete1)

From this point on be sure to always use routerEvents; if you use the router API directly anywhere it will break the setup.

I published next-router-events to make this easier for everyone.

Thanks @jaydenseric!

This thread has been automatically locked because it has not had recent activity. Please open a new issue for related bugs and link to relevant comments in this thread.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

havefive picture havefive  Â·  3Comments

renatorib picture renatorib  Â·  3Comments

swrdfish picture swrdfish  Â·  3Comments

wagerfield picture wagerfield  Â·  3Comments

kenji4569 picture kenji4569  Â·  3Comments