diff --git a/.changeset/fetcher-key-useid.md b/.changeset/fetcher-key-useid.md new file mode 100644 index 0000000000..858dd56cfe --- /dev/null +++ b/.changeset/fetcher-key-useid.md @@ -0,0 +1,5 @@ +--- +"react-router-dom": patch +--- + +Leverage `useId` for internal fetcher keys when available diff --git a/packages/react-router-dom/__tests__/data-browser-router-test.tsx b/packages/react-router-dom/__tests__/data-browser-router-test.tsx index 7034c292a6..0ae3c3824f 100644 --- a/packages/react-router-dom/__tests__/data-browser-router-test.tsx +++ b/packages/react-router-dom/__tests__/data-browser-router-test.tsx @@ -5368,9 +5368,11 @@ function testDomRouter( { window: getWindow("/") } ); let { container } = render(); - expect(container.innerHTML).not.toMatch(/__\d+__,my-key/); + expect(container.innerHTML).not.toMatch(/my-key/); await waitFor(() => - expect(container.innerHTML).toMatch(/__\d+__,my-key/) + // React `useId()` results in either `:r2a:` or `:rp:` depending on + // `DataBrowserRouter`/`DataHashRouter` + expect(container.innerHTML).toMatch(/(:r2a:|:rp:),my-key/) ); }); }); diff --git a/packages/react-router-dom/index.tsx b/packages/react-router-dom/index.tsx index 54f37a1121..52f4b778f5 100644 --- a/packages/react-router-dom/index.tsx +++ b/packages/react-router-dom/index.tsx @@ -396,6 +396,8 @@ const START_TRANSITION = "startTransition"; const startTransitionImpl = React[START_TRANSITION]; const FLUSH_SYNC = "flushSync"; const flushSyncImpl = ReactDOM[FLUSH_SYNC]; +const USE_ID = "useId"; +const useIdImpl = React[USE_ID]; function startTransitionSafe(cb: () => void) { if (startTransitionImpl) { @@ -1634,10 +1636,14 @@ export function useFetcher({ ); // Fetcher key handling - let [fetcherKey, setFetcherKey] = React.useState(key || ""); + // OK to call conditionally to feature detect `useId` + // eslint-disable-next-line react-hooks/rules-of-hooks + let defaultKey = useIdImpl ? useIdImpl() : ""; + let [fetcherKey, setFetcherKey] = React.useState(key || defaultKey); if (key && key !== fetcherKey) { setFetcherKey(key); } else if (!fetcherKey) { + // We will only fall through here when `useId` is not available setFetcherKey(getUniqueFetcherId()); }