diff --git a/packages/@react-aria/ssr/src/SSRProvider.tsx b/packages/@react-aria/ssr/src/SSRProvider.tsx index fe71455c3be..ae5b54e4199 100644 --- a/packages/@react-aria/ssr/src/SSRProvider.tsx +++ b/packages/@react-aria/ssr/src/SSRProvider.tsx @@ -19,7 +19,7 @@ import React, {ReactNode, useContext, useLayoutEffect, useMemo, useState} from ' // and resets the current id counter. This ensures that async loaded components have // consistent ids regardless of the loading order. interface SSRContextValue { - prefix: number, + prefix: string, current: number } @@ -29,7 +29,7 @@ interface SSRContextValue { // will reset this to zero for consistency between server and client, so in the // SSR case multiple copies of React Aria is not supported. const defaultContext: SSRContextValue = { - prefix: Math.round(Math.random() * 10000000000), + prefix: String(Math.round(Math.random() * 10000000000)), current: 0 }; @@ -47,8 +47,9 @@ interface SSRProviderProps { export function SSRProvider(props: SSRProviderProps): JSX.Element { let cur = useContext(SSRContext); let value: SSRContextValue = useMemo(() => ({ - // If this is the first SSRProvider, set to zero, otherwise increment. - prefix: cur === defaultContext ? 0 : ++cur.prefix, + // If this is the first SSRProvider, start with an empty string prefix, otherwise + // append and increment the counter. + prefix: cur === defaultContext ? '' : `${cur.prefix}-${++cur.current}`, current: 0 }), [cur]); @@ -75,7 +76,7 @@ export function useSSRSafeId(defaultId?: string): string { console.warn('When server rendering, you must wrap your application in an to ensure consistent ids are generated between the client and server.'); } - return useMemo(() => defaultId || `react-aria-${ctx.prefix}-${++ctx.current}`, [defaultId]); + return useMemo(() => defaultId || `react-aria${ctx.prefix}-${++ctx.current}`, [defaultId]); } /** diff --git a/packages/@react-aria/ssr/test/SSRProvider.test.js b/packages/@react-aria/ssr/test/SSRProvider.test.js index 67efc9ab407..172c4323693 100644 --- a/packages/@react-aria/ssr/test/SSRProvider.test.js +++ b/packages/@react-aria/ssr/test/SSRProvider.test.js @@ -10,17 +10,17 @@ * governing permissions and limitations under the License. */ -import React from 'react'; -import {render} from '@testing-library/react'; -import {SSRProvider} from '../'; -import {useId} from '@react-aria/utils'; +import React from "react"; +import { render } from "@testing-library/react"; +import { SSRProvider } from "../"; +import { useId } from "@react-aria/utils"; function Test() { return
; } -describe('SSRProvider', function () { - it('it should generate consistent unique ids', function () { +describe("SSRProvider", function () { + it("it should generate consistent unique ids", function () { let tree = render( @@ -28,25 +28,37 @@ describe('SSRProvider', function () { ); - let divs = tree.getAllByTestId('test'); - expect(divs[0].id).toBe('react-aria-0-1'); - expect(divs[1].id).toBe('react-aria-0-2'); + let divs = tree.getAllByTestId("test"); + expect(divs[0].id).toBe("react-aria-1"); + expect(divs[1].id).toBe("react-aria-2"); }); - it('it should generate consistent unique ids with nested SSR providers', function () { + it("it should generate consistent unique ids with nested SSR providers", function () { let tree = render( + + + + + ); - let divs = tree.getAllByTestId('test'); - expect(divs[0].id).toBe('react-aria-1-1'); - expect(divs[1].id).toBe('react-aria-2-1'); + let divs = tree.getAllByTestId("test"); + expect(divs.map((div) => div.id)).toMatchInlineSnapshot(` + Array [ + "react-aria-1", + "react-aria-2-1", + "react-aria-2-2-1", + "react-aria-3", + "react-aria-4-1", + ] + `); }); });