Coping with components shared amongst page router and app router?
Answered
Texas leafcutting ant posted this in #help-forum
Texas leafcutting antOP
Trying to migrate from page router to app router, we want to do it bit by bit, but one of the sticking points is a lot of components consume the router directly, meaning that if they are loaded in the context of an app router page, they fall over. Is there an established pattern to mitigate against this?
Answered by Texas leafcutting ant
import {useContext} from 'react'
import {RouterContext} from 'next/dist/shared/lib/router-context.shared-runtime'
import {AppRouterContext} from 'next/dist/shared/lib/app-router-context.shared-runtime'
import {useParams, usePathname} from 'next/navigation'
import {NextRouter} from 'next/router'
const isPageRouter = (x: unknown): x is NextRouter =>
!!(x as NextRouter).pathname
export const useCombinedRouter = () => {
const pagesRouter = useContext(RouterContext)
const appRouter = useContext(AppRouterContext)
const appRouterPathname = usePathname()
const params = useParams()
const router = pagesRouter ?? appRouter
if (!router) {
throw Error('no Router loaded')
}
return {
push: router.push,
pathname: isPageRouter(router) ? router.pathname : appRouterPathname,
query: isPageRouter(router) ? router.query : params,
}
}something like this will do it
27 Replies
you can keep your components folder like pages dir, and import them in app dir like before
ohh the router you mean
yeah thats a little weird isn't it
Texas leafcutting antOP
yeah, not sure how to get around it
@Texas leafcutting ant im not sure how it will go, but can you try and recreate this: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/link.tsx#L292-L294
Texas leafcutting antOP
@riský this seems interesting
const pagesRouter = React.useContext(RouterContext)
const appRouter = React.useContext(AppRouterContext)
const router = pagesRouter ?? appRouteryeah
but, i think it "may work"
and the useRouter does this anyway: [pages useRouter](https://github.com/vercel/next.js/blob/51fec997f7a8b213031d60fc15cefcbe142afb7c/packages/next/src/client/router.ts#L132-L141) and [app dir useRouter](https://github.com/vercel/next.js/blob/51fec997f7a8b213031d60fc15cefcbe142afb7c/packages/next/src/client/components/navigation.ts#L120-L128)
Texas leafcutting antOP
be interesting to be able to see intersection of the two types, to see what things might fall over in the future
well, as they purposfully make it hard to use both, i think this should be a last resort, but if you re just doing the basics like .push, it should be fine imo
Texas leafcutting antOP
I don't really see why they make it hard to use both, when they're supporting backwards compatibility
making it fiddly just reduces our ability to migrate in stages
they did remove lots from it and do many other changes, so forcing change is the easiest way of keeping it working in pages
just bad for incremental update
Texas leafcutting antOP
import {useContext} from 'react'
import {RouterContext} from 'next/dist/shared/lib/router-context.shared-runtime'
import {AppRouterContext} from 'next/dist/shared/lib/app-router-context.shared-runtime'
import {useParams, usePathname} from 'next/navigation'
import {NextRouter} from 'next/router'
const isPageRouter = (x: unknown): x is NextRouter =>
!!(x as NextRouter).pathname
export const useCombinedRouter = () => {
const pagesRouter = useContext(RouterContext)
const appRouter = useContext(AppRouterContext)
const appRouterPathname = usePathname()
const params = useParams()
const router = pagesRouter ?? appRouter
if (!router) {
throw Error('no Router loaded')
}
return {
push: router.push,
pathname: isPageRouter(router) ? router.pathname : appRouterPathname,
query: isPageRouter(router) ? router.query : params,
}
}something like this will do it
Answer
Texas leafcutting antOP
I think
(in our app we only use these things)
nice
let me know how well this goes 🙂
im not sure if the
usePathname will error in pages dir thoTexas leafcutting antOP
looking at the source, I don't think it will
Texas leafcutting antOP
seems to work...
yay!!
@Texas leafcutting ant so can we mark this as solved!
Texas leafcutting antOP
@riský it's a hack, but yeah I guess