最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Multiple event listeners in Next.js router - Stack Overflow

programmeradmin0浏览0评论

Currently next/router exposes a singleton API where listening to its changes can be done via:

Router.onRouteChangeStart = myHandler // subscribe

Router.onRouteChangeStart = null // unsubscribe

This poses several architecture-related challenges as two unrelated ponents can't listen to route state changes at the same time.

Based on the discussion on .js/issues/2033 there is no plan to convert next/router to an Event Emitter / Observable.

Given that, how can we implement a router with shared subscriptions in Next.js?

Currently next/router exposes a singleton API where listening to its changes can be done via:

Router.onRouteChangeStart = myHandler // subscribe

Router.onRouteChangeStart = null // unsubscribe

This poses several architecture-related challenges as two unrelated ponents can't listen to route state changes at the same time.

Based on the discussion on https://github./zeit/next.js/issues/2033 there is no plan to convert next/router to an Event Emitter / Observable.

Given that, how can we implement a router with shared subscriptions in Next.js?

Share Improve this question asked Oct 16, 2017 at 12:29 Rafal PastuszakRafal Pastuszak 3,1602 gold badges31 silver badges31 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

The solution I've been happy with so far involves wrapping next/router listener methods in Observables and creating a HLA attaching router events to ponents on ponentDidMount.

An example implementation using RxJS:

// I'm using repose for and rxjs, but you should be able to modify this code easily


// 1. sharedRouter.js
import Router from 'next/router'
import { Observable } from 'rxjs'


export const routeChangeStart$ = Observable.create(
    obs => {
        console.log('route: start')
        Router.onRouteChangeStart = url => {
            obs.next(url)
        }
    }
).share() // note the .share() operator,
          // it ensures that we don't reassign Router.onRouteChangeStart
          // every time a new ponent subscribes to this observable

export const routeChangeComplete$ = Observable.create(
    obs => {
        Router.onRouteChangeComplete = () => {
            console.log('route: plete')
            obs.next()
        }
    }
).share()

export const routeChangeError$ = Observable.create(
    obs => {
        Router.onRouteChangeError = () => {
            console.log('route: error')
            obs.next()
        }
    }
).share()

// 2. appBar/withRouterEvents.js
// This one is attached to our AppNav ponent
import { lifecycle } from 'repose'
import * as SharedRouter from './sharedRouter'

const withRouterEvents = lifecycle({
    ponentDidMount(){
        const onStartLoadingSub = Router.routeChangeStart$
            .subscribe(
                () => {
                    // hide nav
                    // show loading indicator
                }
            )

        const onFinishLoadingSub = Router
            .routeChangeError$
            .merge(Router.routeChangeComplete$)
            .subscribe(
                () => {
                    // hide loading indicator
                }
            )

        this.subs = [
            onStartLoadingSub,
            onFinishLoadingSub
        ]
    },

    ponentWillUnmount(){
        if(!Array.isArray(this.subs)) return;
        this.subs.forEach(
            sub => sub.unsubscribe()
        )
    }

})


// 3. appBar/index.js
export default ({
    isNavVisible,
    isLoading,
    children
}) => <nav className={
    isNavVisible ? 'app-bar' : 'app-bar app-bar--hidden'
}>  
    <LoadingIndicator isActive={isLoading} />
    {children}
</nav>

Good news! As from Version of Next.js 6.1.1 multiple router event listeners will be allowed:

Example

Router.events.on('routeChangeStart', (url) => {
  console.log('App is changing to: ', url)
})

Docs

  • Pull Request
  • Documentation
发布评论

评论列表(0)

  1. 暂无评论