Next.js路由器中的多个事件侦听器

时间:2017-10-16 12:29:07

标签: javascript reactjs next.js

目前next/router公开了一个单例API,可以通过以下方式监听其更改:

Router.onRouteChangeStart = myHandler // subscribe

Router.onRouteChangeStart = null // unsubscribe

这带来了一些与架构相关的挑战,因为两个不相关的组件无法同时监听路由状态的变化。

根据对https://github.com/zeit/next.js/issues/2033的讨论,没有计划将next/router转换为事件发射器/可观察者。

鉴于此,我们如何在Next.js中实现具有共享订阅的路由器?

2 个答案:

答案 0 :(得分:1)

到目前为止,我一直很满意的解决方案是在Observables中包含next/router侦听器方法,并在componentDidMount上为组件创建HLA附加路由器事件。

使用RxJS的示例实现:

// I'm using recompose 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 component subscribes to this observable

export const routeChangeComplete$ = Observable.create(
    obs => {
        Router.onRouteChangeComplete = () => {
            console.log('route: complete')
            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 component
import { lifecycle } from 'recompose'
import * as SharedRouter from './sharedRouter'

const withRouterEvents = lifecycle({
    componentDidMount(){
        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
        ]
    },

    componentWillUnmount(){
        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>

答案 1 :(得分:1)

好消息! next.js 6.1.1-canary.2的新金丝雀版本将支持多重路由器事件监听器。

安装

$ npm i next@canary

示例

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

文档