diff --git a/.changeset/thin-plums-drop.md b/.changeset/thin-plums-drop.md new file mode 100644 index 000000000000..ab3fb875aa95 --- /dev/null +++ b/.changeset/thin-plums-drop.md @@ -0,0 +1,5 @@ +--- +'@astrojs/react': patch +--- + +fix a bug where react identifierPrefix was set to null for client:only components causing React.useId to generate ids prefixed with null diff --git a/packages/astro/e2e/fixtures/react-component/src/components/WithId.jsx b/packages/astro/e2e/fixtures/react-component/src/components/WithId.jsx new file mode 100644 index 000000000000..0abe91c72749 --- /dev/null +++ b/packages/astro/e2e/fixtures/react-component/src/components/WithId.jsx @@ -0,0 +1,6 @@ +import React from 'react'; + +export default function () { + const id = React.useId(); + return

{id}

; +} diff --git a/packages/astro/e2e/fixtures/react-component/src/pages/index.astro b/packages/astro/e2e/fixtures/react-component/src/pages/index.astro index f9e0ae395868..a3a0a4c1f0d2 100644 --- a/packages/astro/e2e/fixtures/react-component/src/pages/index.astro +++ b/packages/astro/e2e/fixtures/react-component/src/pages/index.astro @@ -2,6 +2,7 @@ import Counter from '../components/Counter.jsx'; import ReactComponent from '../components/JSXComponent.jsx'; import Suffix from '../components/Suffix.react'; +import WithId from '../components/WithId.jsx'; const someProps = { count: 0, @@ -36,5 +37,11 @@ const someProps = { + + + + + + diff --git a/packages/astro/e2e/react-component.test.js b/packages/astro/e2e/react-component.test.js index 00d747079a71..2d205fc5b80e 100644 --- a/packages/astro/e2e/react-component.test.js +++ b/packages/astro/e2e/react-component.test.js @@ -34,3 +34,22 @@ test.describe('dev', () => { expect(await suffix.textContent()).toBe('suffix toggle true'); }); }); + +test.describe('React client id generation', () => { + test('react components generate unique ids', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/')); + + const components = page.locator('.react-use-id'); + await expect(components).toHaveCount(5); + const staticId = await components.nth(0).getAttribute('id'); + const hydratedId0 = await components.nth(1).getAttribute('id'); + const hydratedId1 = await components.nth(2).getAttribute('id'); + const clientOnlyId0 = await components.nth(3).getAttribute('id'); + const clientOnlyId1 = await components.nth(4).getAttribute('id'); + console.log("ho ho", staticId, hydratedId0, hydratedId1, clientOnlyId0, clientOnlyId1) + expect(staticId).not.toEqual(hydratedId0) + expect(hydratedId0).not.toEqual(hydratedId1) + expect(hydratedId1).not.toEqual(clientOnlyId0) + expect(clientOnlyId0).not.toEqual(clientOnlyId1) + }); +}) diff --git a/packages/integrations/react/client.js b/packages/integrations/react/client.js index ef5929af1387..d8948e7bb7a6 100644 --- a/packages/integrations/react/client.js +++ b/packages/integrations/react/client.js @@ -31,7 +31,7 @@ export default (element) => } if (client === 'only') { return startTransition(() => { - createRoot(element, renderOptions).render(componentEl); + createRoot(element).render(componentEl); }); } return startTransition(() => {