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());
}