diff --git a/packages/next/client/components/navigation.ts b/packages/next/client/components/navigation.ts index 39b3d7092521f..0d5f4dde633fe 100644 --- a/packages/next/client/components/navigation.ts +++ b/packages/next/client/components/navigation.ts @@ -174,10 +174,10 @@ export function useSelectedLayoutSegments( */ export function useSelectedLayoutSegment( parallelRouteKey: string = 'children' -): string { +): string | null { const selectedLayoutSegments = useSelectedLayoutSegments(parallelRouteKey) if (selectedLayoutSegments.length === 0) { - throw new Error('No selected layout segment below the current level') + return null } return selectedLayoutSegments[0] diff --git a/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/first/[dynamic]/(group)/second/[...catchall]/page.js b/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/first/[dynamic]/(group)/second/[...catchall]/page.js index 470730ed05d66..5cda7e23cac8d 100644 --- a/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/first/[dynamic]/(group)/second/[...catchall]/page.js +++ b/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/first/[dynamic]/(group)/second/[...catchall]/page.js @@ -1,11 +1,18 @@ 'use client' -import { useSelectedLayoutSegments } from 'next/navigation' +import { + useSelectedLayoutSegments, + useSelectedLayoutSegment, +} from 'next/navigation' export default function Page() { - const selectedLayoutSegment = useSelectedLayoutSegments() + const selectedLayoutSegments = useSelectedLayoutSegments() + const selectedLayoutSegment = useSelectedLayoutSegment() return ( -
{JSON.stringify(selectedLayoutSegment)}
+ <> +{JSON.stringify(selectedLayoutSegments)}
+{JSON.stringify(selectedLayoutSegment)}
+ > ) } diff --git a/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/first/layout.js b/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/first/layout.js index 6db1338e82783..e79045c5ed1e7 100644 --- a/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/first/layout.js +++ b/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/first/layout.js @@ -1,13 +1,18 @@ 'use client' -import { useSelectedLayoutSegments } from 'next/navigation' +import { + useSelectedLayoutSegments, + useSelectedLayoutSegment, +} from 'next/navigation' export default function Layout({ children }) { - const selectedLayoutSegment = useSelectedLayoutSegments() + const selectedLayoutSegments = useSelectedLayoutSegments() + const selectedLayoutSegment = useSelectedLayoutSegment() return ( <> -{JSON.stringify(selectedLayoutSegment)}
+{JSON.stringify(selectedLayoutSegments)}
+{JSON.stringify(selectedLayoutSegment)}
{children} > ) diff --git a/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/layout.js b/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/layout.js index 5d7974142e40f..3eeae83e65da1 100644 --- a/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/layout.js +++ b/test/e2e/app-dir/app/app/hooks/use-selected-layout-segment/layout.js @@ -1,13 +1,18 @@ 'use client' -import { useSelectedLayoutSegments } from 'next/navigation' +import { + useSelectedLayoutSegments, + useSelectedLayoutSegment, +} from 'next/navigation' export default function Layout({ children }) { - const selectedLayoutSegment = useSelectedLayoutSegments() + const selectedLayoutSegments = useSelectedLayoutSegments() + const selectedLayoutSegment = useSelectedLayoutSegment() return ( <> -{JSON.stringify(selectedLayoutSegment)}
+{JSON.stringify(selectedLayoutSegments)}
+{JSON.stringify(selectedLayoutSegment)}
{children} > ) diff --git a/test/e2e/app-dir/index.test.ts b/test/e2e/app-dir/index.test.ts index b589356462eeb..9917364eb4ef5 100644 --- a/test/e2e/app-dir/index.test.ts +++ b/test/e2e/app-dir/index.test.ts @@ -1273,7 +1273,7 @@ describe('app dir', () => { } }) - describe('useSelectedLayoutSegment', () => { + describe('useSelectedLayoutSegments', () => { it.each` path | outerLayout | innerLayout ${'/hooks/use-selected-layout-segment/first'} | ${['first']} | ${[]} @@ -1303,6 +1303,38 @@ describe('app dir', () => { expect(JSON.parse($('#page-layout-segments').text())).toEqual([]) }) }) + + describe('useSelectedLayoutSegment', () => { + it.each` + path | outerLayout | innerLayout + ${'/hooks/use-selected-layout-segment/first'} | ${'first'} | ${null} + ${'/hooks/use-selected-layout-segment/first/slug1'} | ${'first'} | ${'slug1'} + ${'/hooks/use-selected-layout-segment/first/slug2/second/a/b'} | ${'first'} | ${'slug2'} + `( + 'should have the correct layout segment at $path', + async ({ path, outerLayout, innerLayout }) => { + const html = await renderViaHTTP(next.url, path) + const $ = cheerio.load(html) + + expect(JSON.parse($('#outer-layout-segment').text())).toEqual( + outerLayout + ) + expect(JSON.parse($('#inner-layout-segment').text())).toEqual( + innerLayout + ) + } + ) + + it('should return null in pages', async () => { + const html = await renderViaHTTP( + next.url, + '/hooks/use-selected-layout-segment/first/slug2/second/a/b' + ) + const $ = cheerio.load(html) + + expect(JSON.parse($('#page-layout-segment').text())).toEqual(null) + }) + }) }) if (isDev) {