Skip to content

Commit

Permalink
fix(navigation): allow useSelectedLayoutSegment(s) in Pages Router (#…
Browse files Browse the repository at this point in the history
…62584)

### What?

Do not fail when `useSelectedLayoutSegment` or
`useSelectedLayoutSegments` APIs are called in the Pages Router.

### Why?

This makes migration easier and creates consistency with our other App
Router-specific APIs that inherit the same behavior.

### How?

Similar to #47490, we return `null` if there is no Layout context
(indicating being in Pages Router)

Types are also overridden in the navigation compact module declaration
which kicks in during start to correct the types if we detect a `pages/`
directory.

Note to reviewer: #47490 didn't add a test, so I added one top-level,
let me know if you have a better suggestion for placing.

Closes NEXT-2506
Fixes #61464
  • Loading branch information
balazsorban44 committed Feb 29, 2024
1 parent c353b5f commit 9ae437f
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 4 deletions.
16 changes: 16 additions & 0 deletions packages/next/navigation-types/compat/navigation.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,20 @@ declare module 'next/navigation' {
string | string[]
>
>(): T | null

/**
* A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
* that lets you read the active route segments **below** the Layout it is called from.
*
* If used from `pages/`, the hook will return `null`.
*/
export function useSelectedLayoutSegments(): string[] | null

/**
* A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
* that lets you read the active route segment **one level below** the Layout it is called from.
*
* If used from `pages/`, the hook will return `null`.
*/
export function useSelectedLayoutSegment(): string | null
}
10 changes: 7 additions & 3 deletions packages/next/src/client/components/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,11 @@ function useSelectedLayoutSegments(
parallelRouteKey: string = 'children'
): string[] {
clientHookInServerComponentError('useSelectedLayoutSegments')
const { tree } = useContext(LayoutRouterContext)
return getSelectedLayoutSegmentPath(tree, parallelRouteKey)
const context = useContext(LayoutRouterContext)
// @ts-expect-error This only happens in `pages`. Type is overwritten in navigation.d.ts
if (!context) return null

return getSelectedLayoutSegmentPath(context.tree, parallelRouteKey)
}

/**
Expand All @@ -238,7 +241,8 @@ function useSelectedLayoutSegment(
): string | null {
clientHookInServerComponentError('useSelectedLayoutSegment')
const selectedLayoutSegments = useSelectedLayoutSegments(parallelRouteKey)
if (selectedLayoutSegments.length === 0) {

if (!selectedLayoutSegments || selectedLayoutSegments.length === 0) {
return null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ export const LayoutRouterContext = React.createContext<{
childNodes: CacheNode['parallelRoutes']
tree: FlightRouterState
url: string
}>(null as any)
} | null>(null)

export const GlobalLayoutRouterContext = React.createContext<{
buildId: string
tree: FlightRouterState
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {
useSelectedLayoutSegment,
useSelectedLayoutSegments,
} from 'next/navigation'

export default function Page() {
useSelectedLayoutSegment()
useSelectedLayoutSegments()
return <p id="hello-world">Hello World</p>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { nextTestSetup } from 'e2e-utils'

describe('useSelectedLayoutSegment(s) in Pages Router', () => {
const { next } = nextTestSetup({ files: __dirname })

it('Should render with `useSelectedLayoutSegment(s) hooks', async () => {
const browser = await next.browser('/')

await browser.waitForElementByCss('#hello-world')
expect(await browser.elementByCss('#hello-world').text()).toBe(
'Hello World'
)
})
})

0 comments on commit 9ae437f

Please sign in to comment.