Use underscore instead of « » for useId algorithm (#33422)
Alternative to #33421. The difference is that this also adds an underscore between the "R" and the ID. The reason we wanted to use special characters is because we use the full spectrum of A-Z 0-9 in our ID generation so we can basically collide with any common word (or anyone using a similar algorithm, base64 or even base16). It's a little less likely that someone would put `_R_` specifically unless you generate like two IDs separated by underscore. 
Sebastian Markbåge committed
Jun 3, 2025 at 11:30 UTC
1ae0a845bde5b95dfc319cadf366cb7b3fb1ca92
22 files changed
+85
-96
packages/react-client/src/__tests__/ReactFlight-test.js
+6
-6
@@ -1957,8 +1957,8 @@ describe('ReactFlight', () => {
1957
});
1958
expect(ReactNoop).toMatchRenderedOutput(
1959
<>
1960
- <div prop="«S1»" />
1961
- <div prop="«S2»" />
1960
+ <div prop="_S_1_" />
1961
+ <div prop="_S_2_" />
1962
</>,
1963
);
1964
});
@@ -1981,8 +1981,8 @@ describe('ReactFlight', () => {
1981
});
1982
expect(ReactNoop).toMatchRenderedOutput(
1983
<>
1984
- <div prop="«fooS1»" />
1985
- <div prop="«fooS2»" />
1984
+ <div prop="_fooS_1_" />
1985
+ <div prop="_fooS_2_" />
1986
</>,
1987
);
1988
});
@@ -2021,8 +2021,8 @@ describe('ReactFlight', () => {
2021
assertLog(['ClientDoubler']);
2022
expect(ReactNoop).toMatchRenderedOutput(
2023
<>
2024
- <div prop="«S1»">«S1»</div>
2025
- <div prop="«S1»">«S1»</div>
2024
+ <div prop="_S_1_">_S_1_</div>
2025
+ <div prop="_S_1_">_S_1_</div>
2026
</>,
2027
);
2028
});
packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
+1
-1
@@ -1553,7 +1553,7 @@ describe('ReactHooksInspectionIntegration', () => {
1553
expect(tree[0].id).toEqual(0);
1554
expect(tree[0].isStateEditable).toEqual(false);
1555
expect(tree[0].name).toEqual('Id');
1556
- expect(String(tree[0].value).startsWith('\u00ABr')).toBe(true);
1556
+ expect(String(tree[0].value).startsWith('_r_')).toBe(true);
1557
1558
expect(normalizeSourceLoc(tree)[1]).toMatchInlineSnapshot(`
1559
{
packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
+5
-5
@@ -1082,7 +1082,7 @@ export function makeId(
1082
): string {
1083
const idPrefix = resumableState.idPrefix;
1084
1085
- let id = '\u00AB' + idPrefix + 'R' + treeId;
1085
+ let id = '_' + idPrefix + 'R_' + treeId;
1086
1087
// Unless this is the first id at this level, append a number at the end
1088
// that represents the position of this useId hook among all the useId
@@ -1091,7 +1091,7 @@ export function makeId(
1091
id += 'H' + localId.toString(32);
1092
}
1093
1094
- return id + '\u00BB';
1094
+ return id + '_';
1095
}
1096
1097
function encodeHTMLTextNode(text: string): string {
@@ -5415,7 +5415,7 @@ function writeBlockingRenderInstruction(
5415
): void {
5416
if (enableFizzBlockingRender) {
5417
const idPrefix = resumableState.idPrefix;
5418
- const shellId = '\u00AB' + idPrefix + 'R\u00BB';
5418
+ const shellId = '_' + idPrefix + 'R_';
5419
writeChunk(destination, blockingRenderChunkStart);
5420
writeChunk(destination, stringToChunk(escapeTextForBrowser(shellId)));
5421
writeChunk(destination, blockingRenderChunkEnd);
@@ -5433,7 +5433,7 @@ function writeCompletedShellIdAttribute(
5433
}
5434
resumableState.instructions |= SentCompletedShellId;
5435
const idPrefix = resumableState.idPrefix;
5436
- const shellId = '\u00AB' + idPrefix + 'R\u00BB';
5436
+ const shellId = '_' + idPrefix + 'R_';
5437
writeChunk(destination, completedShellIdAttributeStart);
5438
writeChunk(destination, stringToChunk(escapeTextForBrowser(shellId)));
5439
writeChunk(destination, attributeEnd);
@@ -5448,7 +5448,7 @@ function pushCompletedShellIdAttribute(
5448
}
5449
resumableState.instructions |= SentCompletedShellId;
5450
const idPrefix = resumableState.idPrefix;
5451
- const shellId = '\u00AB' + idPrefix + 'R\u00BB';
5451
+ const shellId = '_' + idPrefix + 'R_';
5452
target.push(
5453
completedShellIdAttributeStart,
5454
stringToChunk(escapeTextForBrowser(shellId)),
packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSetInlineCodeStrings.js
+1
-1
@@ -8,7 +8,7 @@ export const clientRenderBoundary =
8
export const completeBoundary =
9
'$RB=[];$RV=function(c){$RT=performance.now();for(var a=0;a<c.length;a+=2){var b=c[a],h=c[a+1],e=b.parentNode;if(e){var f=b.previousSibling,g=0;do{if(b&&8===b.nodeType){var d=b.data;if("/$"===d||"/&"===d)if(0===g)break;else g--;else"$"!==d&&"$?"!==d&&"$~"!==d&&"$!"!==d&&"&"!==d||g++}d=b.nextSibling;e.removeChild(b);b=d}while(b);for(;h.firstChild;)e.insertBefore(h.firstChild,b);f.data="$";f._reactRetry&&f._reactRetry()}}c.length=0};$RC=function(c,a){if(a=document.getElementById(a))if(a.parentNode.removeChild(a),c=document.getElementById(c))c.previousSibling.data="$~",$RB.push(c,a),2===$RB.length&&setTimeout($RV.bind(null,$RB),("number"!==typeof $RT?0:$RT)+300-performance.now())};';
10
export const completeBoundaryUpgradeToViewTransitions =
11
- '$RV=function(w,f){function h(a,d){var k=a.getAttribute(d);k&&(d=a.style,l.push(a,d.viewTransitionName,d.viewTransitionClass),"auto"!==k&&(d.viewTransitionClass=k),(a=a.getAttribute("vt-name"))||(a="\\u00abT"+F++ +"\\u00bb"),d.viewTransitionName=a,x=!0)}var x=!1,F=0,l=[];try{var e=document.__reactViewTransition;if(e){e.finished.finally($RV.bind(null,f));return}var m=new Map;for(e=1;e<f.length;e+=2)for(var g=f[e].querySelectorAll("[vt-share]"),c=0;c<g.length;c++){var b=g[c];m.set(b.getAttribute("vt-name"),b)}for(g=0;g<f.length;g+=2){var y=f[g],t=y.parentNode;if(t){var r=t.getBoundingClientRect();if(r.left||r.top||r.width||r.height){b=y;for(e=0;b;){if(8===b.nodeType){var p=b.data;if("/$"===p)if(0===e)break;else e--;else"$"!==p&&"$?"!==p&&"$~"!==p&&"$!"!==p||e++}else if(1===b.nodeType){c=b;var z=c.getAttribute("vt-name"),u=m.get(z);h(c,u?"vt-share":"vt-exit");u&&(h(u,"vt-share"),m.set(z,null));var A=c.querySelectorAll("[vt-share]");for(c=0;c<A.length;c++){var B=A[c],C=B.getAttribute("vt-name"),D=m.get(C);\nD&&(h(B,"vt-share"),h(D,"vt-share"),m.set(C,null))}}b=b.nextSibling}for(var q=f[g+1].firstElementChild;q;)null!==m.get(q.getAttribute("vt-name"))&&h(q,"vt-enter"),q=q.nextElementSibling;b=t;do for(var n=b.firstElementChild;n;){var E=n.getAttribute("vt-update");E&&"none"!==E&&!l.includes(n)&&h(n,"vt-update");n=n.nextElementSibling}while((b=b.parentNode)&&1===b.nodeType&&"none"!==b.getAttribute("vt-update"))}}}if(x){var v=document.__reactViewTransition=document.startViewTransition({update:function(){w(f,\ndocument.documentElement.clientHeight);return Promise.race([document.fonts.ready,new Promise(function(a){return setTimeout(a,500)})])},types:[]});v.ready.finally(function(){for(var a=l.length-3;0<=a;a-=3){var d=l[a],k=d.style;k.viewTransitionName=l[a+1];k.viewTransitionClass=l[a+1];""===d.getAttribute("style")&&d.removeAttribute("style")}});v.finished.finally(function(){document.__reactViewTransition===v&&(document.__reactViewTransition=null)});$RB=[];return}}catch(a){}w(f)}.bind(null,$RV);';
11
+ '$RV=function(w,f){function h(a,d){var k=a.getAttribute(d);k&&(d=a.style,l.push(a,d.viewTransitionName,d.viewTransitionClass),"auto"!==k&&(d.viewTransitionClass=k),(a=a.getAttribute("vt-name"))||(a="_T_"+F++ +"_"),d.viewTransitionName=a,x=!0)}var x=!1,F=0,l=[];try{var e=document.__reactViewTransition;if(e){e.finished.finally($RV.bind(null,f));return}var m=new Map;for(e=1;e<f.length;e+=2)for(var g=f[e].querySelectorAll("[vt-share]"),c=0;c<g.length;c++){var b=g[c];m.set(b.getAttribute("vt-name"),b)}for(g=0;g<f.length;g+=2){var y=f[g],t=y.parentNode;if(t){var r=t.getBoundingClientRect();if(r.left||r.top||r.width||r.height){b=y;for(e=0;b;){if(8===b.nodeType){var p=b.data;if("/$"===p)if(0===e)break;else e--;else"$"!==p&&"$?"!==p&&"$~"!==p&&"$!"!==p||e++}else if(1===b.nodeType){c=b;var z=c.getAttribute("vt-name"),u=m.get(z);h(c,u?"vt-share":"vt-exit");u&&(h(u,"vt-share"),m.set(z,null));var A=c.querySelectorAll("[vt-share]");for(c=0;c<A.length;c++){var B=A[c],C=B.getAttribute("vt-name"),D=m.get(C);\nD&&(h(B,"vt-share"),h(D,"vt-share"),m.set(C,null))}}b=b.nextSibling}for(var q=f[g+1].firstElementChild;q;)null!==m.get(q.getAttribute("vt-name"))&&h(q,"vt-enter"),q=q.nextElementSibling;b=t;do for(var n=b.firstElementChild;n;){var E=n.getAttribute("vt-update");E&&"none"!==E&&!l.includes(n)&&h(n,"vt-update");n=n.nextElementSibling}while((b=b.parentNode)&&1===b.nodeType&&"none"!==b.getAttribute("vt-update"))}}}if(x){var v=document.__reactViewTransition=document.startViewTransition({update:function(){w(f,\ndocument.documentElement.clientHeight);return Promise.race([document.fonts.ready,new Promise(function(a){return setTimeout(a,500)})])},types:[]});v.ready.finally(function(){for(var a=l.length-3;0<=a;a-=3){var d=l[a],k=d.style;k.viewTransitionName=l[a+1];k.viewTransitionClass=l[a+1];""===d.getAttribute("style")&&d.removeAttribute("style")}});v.finished.finally(function(){document.__reactViewTransition===v&&(document.__reactViewTransition=null)});$RB=[];return}}catch(a){}w(f)}.bind(null,$RV);';
12
export const completeBoundaryWithStyles =
13
'$RM=new Map;$RR=function(n,w,p){function u(q){this._p=null;q()}for(var r=new Map,t=document,h,b,e=t.querySelectorAll("link[data-precedence],style[data-precedence]"),v=[],k=0;b=e[k++];)"not all"===b.getAttribute("media")?v.push(b):("LINK"===b.tagName&&$RM.set(b.getAttribute("href"),b),r.set(b.dataset.precedence,h=b));e=0;b=[];var l,a;for(k=!0;;){if(k){var f=p[e++];if(!f){k=!1;e=0;continue}var c=!1,m=0;var d=f[m++];if(a=$RM.get(d)){var g=a._p;c=!0}else{a=t.createElement("link");a.href=d;a.rel=\n"stylesheet";for(a.dataset.precedence=l=f[m++];g=f[m++];)a.setAttribute(g,f[m++]);g=a._p=new Promise(function(q,x){a.onload=u.bind(a,q);a.onerror=u.bind(a,x)});$RM.set(d,a)}d=a.getAttribute("media");!g||d&&!matchMedia(d).matches||b.push(g);if(c)continue}else{a=v[e++];if(!a)break;l=a.getAttribute("data-precedence");a.removeAttribute("media")}c=r.get(l)||h;c===h&&(h=a);r.set(l,a);c?c.parentNode.insertBefore(a,c.nextSibling):(c=t.head,c.insertBefore(a,c.firstChild))}if(p=document.getElementById(n))p.previousSibling.data=\n"$~";Promise.all(b).then($RC.bind(null,n,w),$RX.bind(null,n,"CSS failed to load"))};';
14
export const completeSegment =
packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSetShared.js
+1
-1
@@ -111,7 +111,7 @@ export function revealCompletedBoundariesWithViewTransitions(
111
// TODO: We don't have a prefix to pick from here but maybe we don't need it
112
// since it's only applicable temporarily during this specific animation.
113
const idPrefix = '';
114
- name = '\u00AB' + idPrefix + 'T' + autoNameIdx++ + '\u00BB';
114
+ name = '_' + idPrefix + 'T_' + autoNameIdx++ + '_';
115
}
116
elementStyle['viewTransitionName'] = name;
117
shouldStartViewTransition = true;
packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+7
-7
@@ -3587,7 +3587,7 @@ describe('ReactDOMFizzServer', () => {
3587
? '<script src="react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js" async=""></script>'
3588
: '') +
3589
(gate(flags => flags.enableFizzBlockingRender)
3590
- ? '<link rel="expect" href="#«R»" blocking="render">'
3590
+ ? '<link rel="expect" href="#_R_" blocking="render">'
3591
: ''),
3592
);
3593
});
@@ -4197,7 +4197,7 @@ describe('ReactDOMFizzServer', () => {
4197
renderOptions.unstable_externalRuntimeSrc,
4198
).map(n => n.outerHTML),
4199
).toEqual([
4200
- '<script src="foo" id="«R»" async=""></script>',
4200
+ '<script src="foo" id="_R_" async=""></script>',
4201
'<script src="bar" async=""></script>',
4202
'<script src="baz" integrity="qux" async=""></script>',
4203
'<script type="module" src="quux" async=""></script>',
@@ -4284,7 +4284,7 @@ describe('ReactDOMFizzServer', () => {
4284
renderOptions.unstable_externalRuntimeSrc,
4285
).map(n => n.outerHTML),
4286
).toEqual([
4287
- '<script src="foo" id="«R»" async=""></script>',
4287
+ '<script src="foo" id="_R_" async=""></script>',
4288
'<script src="bar" async=""></script>',
4289
'<script src="baz" crossorigin="" async=""></script>',
4290
'<script src="qux" crossorigin="" async=""></script>',
@@ -4523,11 +4523,11 @@ describe('ReactDOMFizzServer', () => {
4523
expect(document.documentElement.innerHTML).toEqual(
4524
'<head><script src="react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js" async=""></script>' +
4525
(gate(flags => flags.enableFizzBlockingRender)
4526
- ? '<link rel="expect" href="#«R»" blocking="render">'
4526
+ ? '<link rel="expect" href="#_R_" blocking="render">'
4527
: '') +
4528
'</head><body><p>hello world!</p>' +
4529
(gate(flags => flags.enableFizzBlockingRender)
4530
- ? '<template id="«R»"></template>'
4530
+ ? '<template id="_R_"></template>'
4531
: '') +
4532
'</body>',
4533
);
@@ -6519,11 +6519,11 @@ describe('ReactDOMFizzServer', () => {
6519
? '<script src="react-dom-bindings/src/server/ReactDOMServerExternalRuntime.js" async=""></script>'
6520
: '') +
6521
(gate(flags => flags.enableFizzBlockingRender)
6522
- ? '<link rel="expect" href="#«R»" blocking="render">'
6522
+ ? '<link rel="expect" href="#_R_" blocking="render">'
6523
: '') +
6524
'</head><body><script>try { foo() } catch (e) {} ;</script>' +
6525
(gate(flags => flags.enableFizzBlockingRender)
6526
- ? '<template id="«R»"></template>'
6526
+ ? '<template id="_R_"></template>'
6527
: '') +
6528
'</body></html>',
6529
);
packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js
+5
-5
@@ -73,7 +73,7 @@ describe('ReactDOMFizzServerBrowser', () => {
73
const result = await readResult(stream);
74
if (gate(flags => flags.enableFizzBlockingRender)) {
75
expect(result).toMatchInlineSnapshot(
76
- `"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
76
+ `"<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head><body>hello world<template id="_R_"></template></body></html>"`,
77
);
78
} else {
79
expect(result).toMatchInlineSnapshot(
@@ -92,7 +92,7 @@ describe('ReactDOMFizzServerBrowser', () => {
92
);
93
const result = await readResult(stream);
94
expect(result).toMatchInlineSnapshot(
95
- `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script id="«R»">INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
95
+ `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script id="_R_">INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
96
);
97
});
98
@@ -524,11 +524,11 @@ describe('ReactDOMFizzServerBrowser', () => {
524
expect(result).toEqual(
525
'<!DOCTYPE html><html><head>' +
526
(gate(flags => flags.enableFizzBlockingRender)
527
- ? '<link rel="expect" href="#«R»" blocking="render"/>'
527
+ ? '<link rel="expect" href="#_R_" blocking="render"/>'
528
: '') +
529
'<title>foo</title></head><body>bar' +
530
(gate(flags => flags.enableFizzBlockingRender)
531
- ? '<template id="«R»"></template>'
531
+ ? '<template id="_R_"></template>'
532
: '') +
533
'</body></html>',
534
);
@@ -548,7 +548,7 @@ describe('ReactDOMFizzServerBrowser', () => {
548
expect(result).toMatchInlineSnapshot(
549
// TODO: remove interpolation because it prevents snapshot updates.
550
// eslint-disable-next-line jest/no-interpolation-in-snapshots
551
- `"<link rel="preload" as="script" fetchPriority="low" nonce="R4nd0m" href="init.js"/><link rel="modulepreload" fetchPriority="low" nonce="R4nd0m" href="init.mjs"/><div>hello world</div><script nonce="${nonce}" id="«R»">INIT();</script><script src="init.js" nonce="${nonce}" async=""></script><script type="module" src="init.mjs" nonce="${nonce}" async=""></script>"`,
551
+ `"<link rel="preload" as="script" fetchPriority="low" nonce="R4nd0m" href="init.js"/><link rel="modulepreload" fetchPriority="low" nonce="R4nd0m" href="init.mjs"/><div>hello world</div><script nonce="${nonce}" id="_R_">INIT();</script><script src="init.js" nonce="${nonce}" async=""></script><script type="module" src="init.mjs" nonce="${nonce}" async=""></script>"`,
552
);
553
});
554
packages/react-dom/src/__tests__/ReactDOMFizzServerEdge-test.js
+1
-1
@@ -73,7 +73,7 @@ describe('ReactDOMFizzServerEdge', () => {
73
74
if (gate(flags => flags.enableFizzBlockingRender)) {
75
expect(result).toMatchInlineSnapshot(
76
- `"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body><main>hello</main><template id="«R»"></template></body></html>"`,
76
+ `"<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head><body><main>hello</main><template id="_R_"></template></body></html>"`,
77
);
78
} else {
79
expect(result).toMatchInlineSnapshot(
packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
+2
-2
@@ -95,7 +95,7 @@ describe('ReactDOMFizzServerNode', () => {
95
// with Float, we emit empty heads if they are elided when rendering <html>
96
if (gate(flags => flags.enableFizzBlockingRender)) {
97
expect(output.result).toMatchInlineSnapshot(
98
- `"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
98
+ `"<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head><body>hello world<template id="_R_"></template></body></html>"`,
99
);
100
} else {
101
expect(output.result).toMatchInlineSnapshot(
@@ -118,7 +118,7 @@ describe('ReactDOMFizzServerNode', () => {
118
pipe(writable);
119
});
120
expect(output.result).toMatchInlineSnapshot(
121
- `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script id="«R»">INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
121
+ `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script id="_R_">INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
122
);
123
});
124
packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js
+12
-12
@@ -186,7 +186,7 @@ describe('ReactDOMFizzStaticBrowser', () => {
186
const prelude = await readContent(result.prelude);
187
if (gate(flags => flags.enableFizzBlockingRender)) {
188
expect(prelude).toMatchInlineSnapshot(
189
- `"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
189
+ `"<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head><body>hello world<template id="_R_"></template></body></html>"`,
190
);
191
} else {
192
expect(prelude).toMatchInlineSnapshot(
@@ -205,7 +205,7 @@ describe('ReactDOMFizzStaticBrowser', () => {
205
);
206
const prelude = await readContent(result.prelude);
207
expect(prelude).toMatchInlineSnapshot(
208
- `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script id="«R»">INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
208
+ `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script id="_R_">INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
209
);
210
});
211
@@ -1434,12 +1434,12 @@ describe('ReactDOMFizzStaticBrowser', () => {
1434
'<!DOCTYPE html><html lang="en"><head>' +
1435
'<link rel="stylesheet" href="my-style" data-precedence="high"/>' +
1436
(gate(flags => flags.enableFizzBlockingRender)
1437
- ? '<link rel="expect" href="#«R»" blocking="render"/>'
1437
+ ? '<link rel="expect" href="#_R_" blocking="render"/>'
1438
: '') +
1439
'</head>' +
1440
'<body>Hello' +
1441
(gate(flags => flags.enableFizzBlockingRender)
1442
- ? '<template id="«R»"></template>'
1442
+ ? '<template id="_R_"></template>'
1443
: '') +
1444
'</body></html>',
1445
);
@@ -1487,8 +1487,8 @@ describe('ReactDOMFizzStaticBrowser', () => {
1487
expect(await readContent(content)).toBe(
1488
'<!DOCTYPE html><html lang="en"><head>' +
1489
'<link rel="stylesheet" href="my-style" data-precedence="high"/>' +
1490
- '<link rel="expect" href="#«R»" blocking="render"/></head>' +
1491
- '<body>Hello<template id="«R»"></template></body></html>',
1490
+ '<link rel="expect" href="#_R_" blocking="render"/></head>' +
1491
+ '<body>Hello<template id="_R_"></template></body></html>',
1492
);
1493
});
1494
@@ -1539,8 +1539,8 @@ describe('ReactDOMFizzStaticBrowser', () => {
1539
expect(await readContent(content)).toBe(
1540
'<!DOCTYPE html><html><head>' +
1541
'<link rel="stylesheet" href="my-style" data-precedence="high"/>' +
1542
- '<link rel="expect" href="#«R»" blocking="render"/></head>' +
1543
- '<body><div>Hello</div><template id="«R»"></template></body></html>',
1542
+ '<link rel="expect" href="#_R_" blocking="render"/></head>' +
1543
+ '<body><div>Hello</div><template id="_R_"></template></body></html>',
1544
);
1545
});
1546
@@ -1622,8 +1622,8 @@ describe('ReactDOMFizzStaticBrowser', () => {
1622
let result = decoder.decode(value, {stream: true});
1623
1624
expect(result).toBe(
1625
- '<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head>' +
1626
- '<body>hello<!--$?--><template id="B:1"></template><!--/$--><script id="«R»">requestAnimationFrame(function(){$RT=performance.now()});</script>',
1625
+ '<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head>' +
1626
+ '<body>hello<!--$?--><template id="B:1"></template><!--/$--><script id="_R_">requestAnimationFrame(function(){$RT=performance.now()});</script>',
1627
);
1628
1629
await 1;
@@ -1647,8 +1647,8 @@ describe('ReactDOMFizzStaticBrowser', () => {
1647
const slice = result.slice(0, instructionIndex + '$RX'.length);
1648
1649
expect(slice).toBe(
1650
- '<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head>' +
1651
- '<body>hello<!--$?--><template id="B:1"></template><!--/$--><script id="«R»">requestAnimationFrame(function(){$RT=performance.now()});</script>' +
1650
+ '<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head>' +
1651
+ '<body>hello<!--$?--><template id="B:1"></template><!--/$--><script id="_R_">requestAnimationFrame(function(){$RT=performance.now()});</script>' +
1652
'<div hidden id="S:1">world<!-- --></div><script>$RX',
1653
);
1654
});
packages/react-dom/src/__tests__/ReactDOMFizzStaticNode-test.js
+2
-2
@@ -65,7 +65,7 @@ describe('ReactDOMFizzStaticNode', () => {
65
const prelude = await readContent(result.prelude);
66
if (gate(flags => flags.enableFizzBlockingRender)) {
67
expect(prelude).toMatchInlineSnapshot(
68
- `"<!DOCTYPE html><html><head><link rel="expect" href="#«R»" blocking="render"/></head><body>hello world<template id="«R»"></template></body></html>"`,
68
+ `"<!DOCTYPE html><html><head><link rel="expect" href="#_R_" blocking="render"/></head><body>hello world<template id="_R_"></template></body></html>"`,
69
);
70
} else {
71
expect(prelude).toMatchInlineSnapshot(
@@ -86,7 +86,7 @@ describe('ReactDOMFizzStaticNode', () => {
86
);
87
const prelude = await readContent(result.prelude);
88
expect(prelude).toMatchInlineSnapshot(
89
- `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script id="«R»">INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
89
+ `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script id="_R_">INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
90
);
91
});
92
packages/react-dom/src/__tests__/ReactDOMFizzViewTransition-test.js
+2
-2
@@ -303,7 +303,7 @@ describe('ReactDOMFizzViewTransition', () => {
303
304
expect(getVisibleChildren(container)).toEqual(
305
<div>
306
- <div vt-name="«R0»" vt-update="auto" vt-share="auto">
306
+ <div vt-name="_R_0_" vt-update="auto" vt-share="auto">
307
<span vt-update="auto">Loading</span>
308
</div>
309
</div>,
@@ -321,7 +321,7 @@ describe('ReactDOMFizzViewTransition', () => {
321
322
expect(getVisibleChildren(container)).toEqual(
323
<div>
324
- <div vt-name="«R0»" vt-update="auto" vt-share="auto">
324
+ <div vt-name="_R_0_" vt-update="auto" vt-share="auto">
325
<span vt-update="auto">Content</span>
326
</div>
327
</div>,
packages/react-dom/src/__tests__/ReactDOMFloat-test.js
+2
-2
@@ -707,12 +707,12 @@ describe('ReactDOMFloat', () => {
707
? '<script src="react-dom/unstable_server-external-runtime" async=""></script>'
708
: '') +
709
(gate(flags => flags.enableFizzBlockingRender)
710
- ? '<link rel="expect" href="#«R»" blocking="render"/>'
710
+ ? '<link rel="expect" href="#_R_" blocking="render"/>'
711
: '') +
712
'<title>foo</title></head>' +
713
'<body>bar' +
714
(gate(flags => flags.enableFizzBlockingRender)
715
- ? '<template id="«R»"></template>'
715
+ ? '<template id="_R_"></template>'
716
: ''),
717
'</body></html>',
718
]);
packages/react-dom/src/__tests__/ReactDOMLegacyFloat-test.js
+2
-2
@@ -36,11 +36,11 @@ describe('ReactDOMFloat', () => {
36
expect(result).toEqual(
37
'<html><head><meta charSet="utf-8"/>' +
38
(gate(flags => flags.enableFizzBlockingRender)
39
- ? '<link rel="expect" href="#«R»" blocking="render"/>'
39
+ ? '<link rel="expect" href="#_R_" blocking="render"/>'
40
: '') +
41
'<title>title</title><script src="foo"></script></head>' +
42
(gate(flags => flags.enableFizzBlockingRender)
43
- ? '<template id="«R»"></template>'
43
+ ? '<template id="_R_"></template>'
44
: '') +
45
'</html>',
46
);
packages/react-dom/src/__tests__/ReactDOMUseId-test.js
+15
-15
@@ -96,7 +96,7 @@ describe('useId', () => {
96
}
97
98
function normalizeTreeIdForTesting(id) {
99
- const result = id.match(/\u00AB(R|r)([a-z0-9]*)(H([0-9]*))?\u00BB/);
99
+ const result = id.match(/_(R|r)_([a-z0-9]*)(H([0-9]*))?_/);
100
if (result === undefined) {
101
throw new Error('Invalid id format');
102
}
@@ -285,7 +285,7 @@ describe('useId', () => {
285
// 'R:' prefix, and the first character after that, which may not correspond
286
// to a complete set of 5 bits.
287
//
288
- // Example: «Rclalalalalalalala...:
288
+ // Example: _Rclalalalalalalala...:
289
//
290
// We can use this pattern to test large ids that exceed the bitwise
291
// safe range (32 bits). The algorithm should theoretically support ids
@@ -320,8 +320,8 @@ describe('useId', () => {
320
321
// Confirm that every id matches the expected pattern
322
for (let i = 0; i < divs.length; i++) {
323
- // Example: «Rclalalalalalalala...:
324
- expect(divs[i].id).toMatch(/^\u00ABR.(((al)*a?)((la)*l?))*\u00BB$/);
323
+ // Example: _Rclalalalalalalala...:
324
+ expect(divs[i].id).toMatch(/^_R_.(((al)*a?)((la)*l?))*_$/);
325
}
326
});
327
@@ -345,7 +345,7 @@ describe('useId', () => {
345
<div
346
id="container"
347
>
348
- «R0», «R0H1», «R0H2»
348
+ _R_0_, _R_0H1_, _R_0H2_
349
</div>
350
`);
351
});
@@ -370,7 +370,7 @@ describe('useId', () => {
370
<div
371
id="container"
372
>
373
- «R0»
373
+ _R_0_
374
</div>
375
`);
376
});
@@ -608,10 +608,10 @@ describe('useId', () => {
608
id="container"
609
>
610
<div>
611
- «custom-prefix-R1»
611
+ _custom-prefix-R_1_
612
</div>
613
<div>
614
- «custom-prefix-R2»
614
+ _custom-prefix-R_2_
615
</div>
616
</div>
617
`);
@@ -625,13 +625,13 @@ describe('useId', () => {
625
id="container"
626
>
627
<div>
628
- «custom-prefix-R1»
628
+ _custom-prefix-R_1_
629
</div>
630
<div>
631
- «custom-prefix-R2»
631
+ _custom-prefix-R_2_
632
</div>
633
<div>
634
- «custom-prefix-r0»
634
+ _custom-prefix-r_0_
635
</div>
636
</div>
637
`);
@@ -672,11 +672,11 @@ describe('useId', () => {
672
id="container"
673
>
674
<div>
675
- «R0»
675
+ _R_0_
676
<!-- -->
677
678
<div>
679
- «R7»
679
+ _R_7_
680
</div>
681
</div>
682
</div>
@@ -690,11 +690,11 @@ describe('useId', () => {
690
id="container"
691
>
692
<div>
693
- «R0»
693
+ _R_0_
694
<!-- -->
695
696
<div>
697
- «R7»
697
+ _R_7_
698
</div>
699
</div>
700
</div>
packages/react-dom/src/__tests__/ReactRenderDocument-test.js
+9
-9
@@ -80,7 +80,7 @@ describe('rendering React components at document', () => {
80
expect(testDocument.body.innerHTML).toBe(
81
'Hello world' +
82
(gate(flags => flags.enableFizzBlockingRender)
83
- ? '<template id="«R»"></template>'
83
+ ? '<template id="_R_"></template>'
84
: ''),
85
);
86
@@ -90,7 +90,7 @@ describe('rendering React components at document', () => {
90
expect(testDocument.body.innerHTML).toBe(
91
'Hello moon' +
92
(gate(flags => flags.enableFizzBlockingRender)
93
- ? '<template id="«R»"></template>'
93
+ ? '<template id="_R_"></template>'
94
: ''),
95
);
96
@@ -120,7 +120,7 @@ describe('rendering React components at document', () => {
120
expect(testDocument.body.innerHTML).toBe(
121
'Hello world' +
122
(gate(flags => flags.enableFizzBlockingRender)
123
- ? '<template id="«R»"></template>'
123
+ ? '<template id="_R_"></template>'
124
: ''),
125
);
126
@@ -135,12 +135,12 @@ describe('rendering React components at document', () => {
135
expect(testDocument.body).toBe(originalBody);
136
expect(originalBody.innerHTML).toBe(
137
gate(flags => flags.enableFizzBlockingRender)
138
- ? '<template id="«R»"></template>'
138
+ ? '<template id="_R_"></template>'
139
: '',
140
);
141
expect(originalHead.innerHTML).toBe(
142
gate(flags => flags.enableFizzBlockingRender)
143
- ? '<link rel="expect" href="#«R»" blocking="render">'
143
+ ? '<link rel="expect" href="#_R_" blocking="render">'
144
: '',
145
);
146
});
@@ -183,7 +183,7 @@ describe('rendering React components at document', () => {
183
expect(testDocument.body.innerHTML).toBe(
184
'Hello world' +
185
(gate(flags => flags.enableFizzBlockingRender)
186
- ? '<template id="«R»"></template>'
186
+ ? '<template id="_R_"></template>'
187
: ''),
188
);
189
@@ -193,7 +193,7 @@ describe('rendering React components at document', () => {
193
194
expect(testDocument.body.innerHTML).toBe(
195
(gate(flags => flags.enableFizzBlockingRender)
196
- ? '<template id="«R»"></template>'
196
+ ? '<template id="_R_"></template>'
197
: '') + 'Goodbye world',
198
);
199
});
@@ -227,7 +227,7 @@ describe('rendering React components at document', () => {
227
expect(testDocument.body.innerHTML).toBe(
228
'Hello world' +
229
(gate(flags => flags.enableFizzBlockingRender)
230
- ? '<template id="«R»"></template>'
230
+ ? '<template id="_R_"></template>'
231
: ''),
232
);
233
});
@@ -366,7 +366,7 @@ describe('rendering React components at document', () => {
366
? 'Hello world'
367
: 'Goodbye world' +
368
(gate(flags => flags.enableFizzBlockingRender)
369
- ? '<template id="«R»"></template>'
369
+ ? '<template id="_R_"></template>'
370
: ''),
371
);
372
});
packages/react-reconciler/src/ReactFiberHooks.js
+3
-8
@@ -3446,7 +3446,7 @@ function mountId(): string {
3446
const treeId = getTreeId();
3447
3448
// Use a captial R prefix for server-generated ids.
3449
- id = '\u00AB' + identifierPrefix + 'R' + treeId;
3449
+ id = '_' + identifierPrefix + 'R_' + treeId;
3450
3451
// Unless this is the first id at this level, append a number at the end
3452
// that represents the position of this useId hook among all the useId
@@ -3456,16 +3456,11 @@ function mountId(): string {
3456
id += 'H' + localId.toString(32);
3457
}
3458
3459
- id += '\u00BB';
3459
+ id += '_';
3460
} else {
3461
// Use a lowercase r prefix for client-generated ids.
3462
const globalClientId = globalClientIdCounter++;
3463
- id =
3464
- '\u00AB' +
3465
- identifierPrefix +
3466
- 'r' +
3467
- globalClientId.toString(32) +
3468
- '\u00BB';
3463
+ id = '_' + identifierPrefix + 'r_' + globalClientId.toString(32) + '_';
3464
}
3465
3466
hook.memoizedState = id;
packages/react-reconciler/src/ReactFiberViewTransitionComponent.js
+1
-1
@@ -41,7 +41,7 @@ export function getViewTransitionName(
41
const identifierPrefix = root.identifierPrefix;
42
const globalClientId = globalClientIdCounter++;
43
const name =
44
- '\u00AB' + identifierPrefix + 't' + globalClientId.toString(32) + '\u00BB';
44
+ '_' + identifierPrefix + 't_' + globalClientId.toString(32) + '_';
45
instance.autoName = name;
46
return name;
47
}
packages/react-server-dom-fb/src/__tests__/ReactDOMServerFB-test.internal.js
+1
-1
@@ -59,7 +59,7 @@ describe('ReactDOMServerFB', () => {
59
});
60
const result = readResult(stream);
61
expect(result).toMatchInlineSnapshot(
62
- `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script id="«R»">INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
62
+ `"<link rel="preload" as="script" fetchPriority="low" href="init.js"/><link rel="modulepreload" fetchPriority="low" href="init.mjs"/><div>hello world</div><script id="_R_">INIT();</script><script src="init.js" async=""></script><script type="module" src="init.mjs" async=""></script>"`,
63
);
64
});
65
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js
+4
-4
@@ -1909,12 +1909,12 @@ describe('ReactFlightDOM', () => {
1909
'<!DOCTYPE html><html><head><link rel="preload" href="before1" as="style"/>' +
1910
'<link rel="preload" href="after1" as="style"/>' +
1911
(gate(flags => flags.enableFizzBlockingRender)
1912
- ? '<link rel="expect" href="#«R»" blocking="render"/>'
1912
+ ? '<link rel="expect" href="#_R_" blocking="render"/>'
1913
: '') +
1914
'</head>' +
1915
'<body><p>hello world</p>' +
1916
(gate(flags => flags.enableFizzBlockingRender)
1917
- ? '<template id="«R»"></template>'
1917
+ ? '<template id="_R_"></template>'
1918
: '') +
1919
'</body></html>',
1920
);
@@ -1922,12 +1922,12 @@ describe('ReactFlightDOM', () => {
1922
'<!DOCTYPE html><html><head><link rel="preload" href="before2" as="style"/>' +
1923
'<link rel="preload" href="after2" as="style"/>' +
1924
(gate(flags => flags.enableFizzBlockingRender)
1925
- ? '<link rel="expect" href="#«R»" blocking="render"/>'
1925
+ ? '<link rel="expect" href="#_R_" blocking="render"/>'
1926
: '') +
1927
'</head>' +
1928
'<body><p>hello world</p>' +
1929
(gate(flags => flags.enableFizzBlockingRender)
1930
- ? '<template id="«R»"></template>'
1930
+ ? '<template id="_R_"></template>'
1931
: '') +
1932
'</body></html>',
1933
);
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js
+2
-2
@@ -1888,12 +1888,12 @@ describe('ReactFlightDOMBrowser', () => {
1888
expect(content).toEqual(
1889
'<!DOCTYPE html><html><head>' +
1890
(gate(flags => flags.enableFizzBlockingRender)
1891
- ? '<link rel="expect" href="#«R»" blocking="render"/>'
1891
+ ? '<link rel="expect" href="#_R_" blocking="render"/>'
1892
: '') +
1893
'</head>' +
1894
'<body><p>hello world</p>' +
1895
(gate(flags => flags.enableFizzBlockingRender)
1896
- ? '<template id="«R»"></template>'
1896
+ ? '<template id="_R_"></template>'
1897
: '') +
1898
'</body></html>',
1899
);
packages/react-server/src/ReactFlightHooks.js
+1
-7
@@ -120,13 +120,7 @@ function useId(): string {
120
}
121
const id = currentRequest.identifierCount++;
122
// use 'S' for Flight components to distinguish from 'R' and 'r' in Fizz/Client
123
- return (
124
- '\u00AB' +
125
- currentRequest.identifierPrefix +
126
- 'S' +
127
- id.toString(32) +
128
- '\u00BB'
129
- );
123
+ return '_' + currentRequest.identifierPrefix + 'S_' + id.toString(32) + '_';
124
}
125
126
function use<T>(usable: Usable<T>): T {