diff --git a/packages/next/client/components/navigation.ts b/packages/next/client/components/navigation.ts index 39b3d7092521fb7..0d5f4dde633feb4 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 470730ed05d66d3..5cda7e23cac8d81 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 6db1338e8278364..e79045c5ed1e7be 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 5d7974142e40f6d..3eeae83e65da1be 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 b589356462eebbf..9917364eb4ef5e1 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) {