diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
index 5b36039ecc5dc..f5003e96bdf6c 100644
--- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
+++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
@@ -614,7 +614,7 @@ describe('ReactHooksInspectionIntegration', () => {
expect(tree[0].id).toEqual(0);
expect(tree[0].isStateEditable).toEqual(false);
expect(tree[0].name).toEqual('Id');
- expect(String(tree[0].value).startsWith('r:')).toBe(true);
+ expect(String(tree[0].value).startsWith(':r')).toBe(true);
expect(tree[1]).toEqual({
id: 1,
diff --git a/packages/react-dom/src/__tests__/ReactDOMUseId-test.js b/packages/react-dom/src/__tests__/ReactDOMUseId-test.js
index 036c138d5e97a..41c4ddcbcc489 100644
--- a/packages/react-dom/src/__tests__/ReactDOMUseId-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMUseId-test.js
@@ -93,7 +93,11 @@ describe('useId', () => {
}
function normalizeTreeIdForTesting(id) {
- const [serverClientPrefix, base32, hookIndex] = id.split(':');
+ const result = id.match(/:(R|r)(.*):(([0-9]*):)?/);
+ if (result === undefined) {
+ throw new Error('Invalid id format');
+ }
+ const [, serverClientPrefix, base32, hookIndex] = result;
if (serverClientPrefix.endsWith('r')) {
// Client ids aren't stable. For testing purposes, strip out the counter.
return (
@@ -278,7 +282,7 @@ describe('useId', () => {
// 'R:' prefix, and the first character after that, which may not correspond
// to a complete set of 5 bits.
//
- // Example: R:clalalalalalalala...
+ // Example: :Rclalalalalalalala...:
//
// We can use this pattern to test large ids that exceed the bitwise
// safe range (32 bits). The algorithm should theoretically support ids
@@ -313,8 +317,8 @@ describe('useId', () => {
// Confirm that every id matches the expected pattern
for (let i = 0; i < divs.length; i++) {
- // Example: R:clalalalalalalala...
- expect(divs[i].id).toMatch(/^R:.(((al)*a?)((la)*l?))*$/);
+ // Example: :Rclalalalalalalala...:
+ expect(divs[i].id).toMatch(/^:R.(((al)*a?)((la)*l?))*:$/);
}
});
@@ -338,7 +342,7 @@ describe('useId', () => {
- R:0, R:0:1, R:0:2
+ :R0:, :R0:1:, :R0:2:
`);
@@ -364,7 +368,7 @@ describe('useId', () => {
- R:0
+ :R0:
`);
@@ -603,10 +607,10 @@ describe('useId', () => {
id="container"
>
- custom-prefix-R:1
+ :custom-prefix-R1:
- custom-prefix-R:2
+ :custom-prefix-R2:
`);
@@ -620,13 +624,13 @@ describe('useId', () => {
id="container"
>
- custom-prefix-R:1
+ :custom-prefix-R1:
- custom-prefix-R:2
+ :custom-prefix-R2:
- custom-prefix-r:0
+ :custom-prefix-r0:
`);
diff --git a/packages/react-dom/src/server/ReactDOMServerFormatConfig.js b/packages/react-dom/src/server/ReactDOMServerFormatConfig.js
index 20887c226015a..f623556bb62de 100644
--- a/packages/react-dom/src/server/ReactDOMServerFormatConfig.js
+++ b/packages/react-dom/src/server/ReactDOMServerFormatConfig.js
@@ -130,7 +130,7 @@ export function createResponseState(
placeholderPrefix: stringToPrecomputedChunk(idPrefix + 'P:'),
segmentPrefix: stringToPrecomputedChunk(idPrefix + 'S:'),
boundaryPrefix: idPrefix + 'B:',
- idPrefix: idPrefix + 'R:',
+ idPrefix: idPrefix,
nextSuspenseID: 0,
sentCompleteSegmentFunction: false,
sentCompleteBoundaryFunction: false,
@@ -242,13 +242,13 @@ export function makeId(
): string {
const idPrefix = responseState.idPrefix;
- let id = idPrefix + treeId;
+ let id = ':' + idPrefix + 'R' + treeId + ':';
// Unless this is the first id at this level, append a number at the end
// that represents the position of this useId hook among all the useId
// hooks for this fiber.
if (localId > 0) {
- id += ':' + localId.toString(32);
+ id += localId.toString(32) + ':';
}
return id;
diff --git a/packages/react-reconciler/src/ReactFiberHooks.new.js b/packages/react-reconciler/src/ReactFiberHooks.new.js
index 3f64a7d8f9178..5c4b9357f909e 100644
--- a/packages/react-reconciler/src/ReactFiberHooks.new.js
+++ b/packages/react-reconciler/src/ReactFiberHooks.new.js
@@ -2072,19 +2072,19 @@ function mountId(): string {
const treeId = getTreeId();
// Use a captial R prefix for server-generated ids.
- id = identifierPrefix + 'R:' + treeId;
+ id = ':' + identifierPrefix + 'R' + treeId + ':';
// Unless this is the first id at this level, append a number at the end
// that represents the position of this useId hook among all the useId
// hooks for this fiber.
const localId = localIdCounter++;
if (localId > 0) {
- id += ':' + localId.toString(32);
+ id += localId.toString(32) + ':';
}
} else {
// Use a lowercase r prefix for client-generated ids.
const globalClientId = globalClientIdCounter++;
- id = identifierPrefix + 'r:' + globalClientId.toString(32);
+ id = ':' + identifierPrefix + 'r' + globalClientId.toString(32) + ':';
}
hook.memoizedState = id;
diff --git a/packages/react-reconciler/src/ReactFiberHooks.old.js b/packages/react-reconciler/src/ReactFiberHooks.old.js
index d55cac9b26c74..f0fcef733d581 100644
--- a/packages/react-reconciler/src/ReactFiberHooks.old.js
+++ b/packages/react-reconciler/src/ReactFiberHooks.old.js
@@ -2072,19 +2072,19 @@ function mountId(): string {
const treeId = getTreeId();
// Use a captial R prefix for server-generated ids.
- id = identifierPrefix + 'R:' + treeId;
+ id = ':' + identifierPrefix + 'R' + treeId + ':';
// Unless this is the first id at this level, append a number at the end
// that represents the position of this useId hook among all the useId
// hooks for this fiber.
const localId = localIdCounter++;
if (localId > 0) {
- id += ':' + localId.toString(32);
+ id += localId.toString(32) + ':';
}
} else {
// Use a lowercase r prefix for client-generated ids.
const globalClientId = globalClientIdCounter++;
- id = identifierPrefix + 'r:' + globalClientId.toString(32);
+ id = ':' + identifierPrefix + 'r' + globalClientId.toString(32) + ':';
}
hook.memoizedState = id;