Skip to content

Commit 5d08a24

Browse files
authored
useId: Use 'H' to separate main id from hook index (#23363)
No id should be a subset of any other id. Currently, this is not true when there are multiple hooks in the same component. We append the hook index to the end of the id, except for the first one. So you get this pattern. Before this change: - 1st hook's id: :R0: - 2nd hook's id: :R0:1: The first hook's id is a subset of all the other ids in the same component. The fix for this is to use a different character to separate the main id from the hook index. I've chosen a captial 'H' for this because capital letters are not part of the base 32 character set when encoding with `toString(32)`. After this change: - 1st hook's id: :R0: - 2nd hook's id: :R0H1:
1 parent 629036a commit 5d08a24

File tree

4 files changed

+13
-9
lines changed

4 files changed

+13
-9
lines changed

packages/react-dom/src/__tests__/ReactDOMUseId-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ describe('useId', () => {
9393
}
9494

9595
function normalizeTreeIdForTesting(id) {
96-
const result = id.match(/:(R|r)(.*):(([0-9]*):)?/);
96+
const result = id.match(/:(R|r)([a-z0-9]*)(H([0-9]*))?:/);
9797
if (result === undefined) {
9898
throw new Error('Invalid id format');
9999
}
@@ -342,7 +342,7 @@ describe('useId', () => {
342342
<div
343343
id="container"
344344
>
345-
:R0:, :R0:1:, :R0:2:
345+
:R0:, :R0H1:, :R0H2:
346346
<!-- -->
347347
</div>
348348
`);

packages/react-dom/src/server/ReactDOMServerFormatConfig.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,16 +242,16 @@ export function makeId(
242242
): string {
243243
const idPrefix = responseState.idPrefix;
244244

245-
let id = ':' + idPrefix + 'R' + treeId + ':';
245+
let id = ':' + idPrefix + 'R' + treeId;
246246

247247
// Unless this is the first id at this level, append a number at the end
248248
// that represents the position of this useId hook among all the useId
249249
// hooks for this fiber.
250250
if (localId > 0) {
251-
id += localId.toString(32) + ':';
251+
id += 'H' + localId.toString(32);
252252
}
253253

254-
return id;
254+
return id + ':';
255255
}
256256

257257
function encodeHTMLTextNode(text: string): string {

packages/react-reconciler/src/ReactFiberHooks.new.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,15 +2072,17 @@ function mountId(): string {
20722072
const treeId = getTreeId();
20732073

20742074
// Use a captial R prefix for server-generated ids.
2075-
id = ':' + identifierPrefix + 'R' + treeId + ':';
2075+
id = ':' + identifierPrefix + 'R' + treeId;
20762076

20772077
// Unless this is the first id at this level, append a number at the end
20782078
// that represents the position of this useId hook among all the useId
20792079
// hooks for this fiber.
20802080
const localId = localIdCounter++;
20812081
if (localId > 0) {
2082-
id += localId.toString(32) + ':';
2082+
id += 'H' + localId.toString(32);
20832083
}
2084+
2085+
id += ':';
20842086
} else {
20852087
// Use a lowercase r prefix for client-generated ids.
20862088
const globalClientId = globalClientIdCounter++;

packages/react-reconciler/src/ReactFiberHooks.old.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,15 +2072,17 @@ function mountId(): string {
20722072
const treeId = getTreeId();
20732073

20742074
// Use a captial R prefix for server-generated ids.
2075-
id = ':' + identifierPrefix + 'R' + treeId + ':';
2075+
id = ':' + identifierPrefix + 'R' + treeId;
20762076

20772077
// Unless this is the first id at this level, append a number at the end
20782078
// that represents the position of this useId hook among all the useId
20792079
// hooks for this fiber.
20802080
const localId = localIdCounter++;
20812081
if (localId > 0) {
2082-
id += localId.toString(32) + ':';
2082+
id += 'H' + localId.toString(32);
20832083
}
2084+
2085+
id += ':';
20842086
} else {
20852087
// Use a lowercase r prefix for client-generated ids.
20862088
const globalClientId = globalClientIdCounter++;

0 commit comments

Comments
 (0)