Remove experimental useOpaqueIdentifier API (#22672)
useId is the updated version of this API.
Andrew Clark committed
Nov 1, 2021 at 18:02 UTC
75f3ddebfa0d9885ce8df42571cf0c09ad6c0a3b
39 files changed
+22
-1790
packages/react-art/src/ReactARTHostConfig.js
-18
@@ -436,24 +436,6 @@ export function getInstanceFromNode(node) {
436
throw new Error('Not implemented.');
437
}
438
439
-export function isOpaqueHydratingObject(value: mixed): boolean {
440
- throw new Error('Not implemented.');
441
-}
442
-
443
-export function makeOpaqueHydratingObject(
444
- attemptToReadValue: () => void,
445
-): OpaqueIDType {
446
- throw new Error('Not implemented.');
447
-}
448
-
449
-export function makeClientId(): OpaqueIDType {
450
- throw new Error('Not implemented.');
451
-}
452
-
453
-export function makeClientIdInDEV(warnOnAccessInDEV: () => void): OpaqueIDType {
454
- throw new Error('Not implemented.');
455
-}
456
-
439
export function beforeActiveInstanceBlur(internalInstanceHandle: Object) {
440
// noop
441
}
packages/react-debug-tools/src/ReactDebugHooks.js
-26
@@ -18,13 +18,9 @@ import type {
18
Fiber,
19
Dispatcher as DispatcherType,
20
} from 'react-reconciler/src/ReactInternalTypes';
21
-import type {OpaqueIDType} from 'react-reconciler/src/ReactFiberHostConfig';
22
-
23
-import {NoMode} from 'react-reconciler/src/ReactTypeOfMode';
21
22
import ErrorStackParser from 'error-stack-parser';
23
import ReactSharedInternals from 'shared/ReactSharedInternals';
27
-import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
24
import {
25
FunctionComponent,
26
SimpleMemoComponent,
@@ -53,8 +49,6 @@ type Dispatch<A> = A => void;
49
50
let primitiveStackCache: null | Map<string, Array<any>> = null;
51
56
-let currentFiber: Fiber | null = null;
57
-
52
type Hook = {
53
memoizedState: any,
54
next: Hook | null,
@@ -324,23 +318,6 @@ function useDeferredValue<T>(value: T): T {
318
return value;
319
}
320
327
-function useOpaqueIdentifier(): OpaqueIDType | void {
328
- const hook = nextHook(); // State
329
- if (currentFiber && currentFiber.mode === NoMode) {
330
- nextHook(); // Effect
331
- }
332
- let value = hook === null ? undefined : hook.memoizedState;
333
- if (value && value.$$typeof === REACT_OPAQUE_ID_TYPE) {
334
- value = undefined;
335
- }
336
- hookLog.push({
337
- primitive: 'OpaqueIdentifier',
338
- stackError: new Error(),
339
- value,
340
- });
341
- return value;
342
-}
343
-
321
function useId(): string {
322
const hook = nextHook();
323
const id = hook !== null ? hook.memoizedState : '';
@@ -371,7 +348,6 @@ const Dispatcher: DispatcherType = {
348
useMutableSource,
349
useSyncExternalStore,
350
useDeferredValue,
374
- useOpaqueIdentifier,
351
useId,
352
};
353
@@ -767,8 +743,6 @@ export function inspectHooksOfFiber(
743
currentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
744
}
745
770
- currentFiber = fiber;
771
-
746
if (
747
fiber.tag !== FunctionComponent &&
748
fiber.tag !== SimpleMemoComponent &&
packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
-58
@@ -598,64 +598,6 @@ describe('ReactHooksInspectionIntegration', () => {
598
]);
599
});
600
601
- it('should support composite useOpaqueIdentifier hook', () => {
602
- function Foo(props) {
603
- const id = React.unstable_useOpaqueIdentifier();
604
- const [state] = React.useState(() => 'hello', []);
605
- return <div id={id}>{state}</div>;
606
- }
607
-
608
- const renderer = ReactTestRenderer.create(<Foo />);
609
- const childFiber = renderer.root.findByType(Foo)._currentFiber();
610
- const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
611
-
612
- expect(tree.length).toEqual(2);
613
-
614
- expect(tree[0].id).toEqual(0);
615
- expect(tree[0].isStateEditable).toEqual(false);
616
- expect(tree[0].name).toEqual('OpaqueIdentifier');
617
- expect(String(tree[0].value).startsWith('c_')).toBe(true);
618
-
619
- expect(tree[1]).toEqual({
620
- id: 1,
621
- isStateEditable: true,
622
- name: 'State',
623
- value: 'hello',
624
- subHooks: [],
625
- });
626
- });
627
-
628
- it('should support composite useOpaqueIdentifier hook in concurrent mode', () => {
629
- function Foo(props) {
630
- const id = React.unstable_useOpaqueIdentifier();
631
- const [state] = React.useState('hello');
632
- return <div id={id}>{state}</div>;
633
- }
634
-
635
- const renderer = ReactTestRenderer.create(<Foo />, {
636
- unstable_isConcurrent: true,
637
- });
638
- expect(Scheduler).toFlushWithoutYielding();
639
-
640
- const childFiber = renderer.root.findByType(Foo)._currentFiber();
641
- const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
642
-
643
- expect(tree.length).toEqual(2);
644
-
645
- expect(tree[0].id).toEqual(0);
646
- expect(tree[0].isStateEditable).toEqual(false);
647
- expect(tree[0].name).toEqual('OpaqueIdentifier');
648
- expect(String(tree[0].value).startsWith('c_')).toBe(true);
649
-
650
- expect(tree[1]).toEqual({
651
- id: 1,
652
- isStateEditable: true,
653
- name: 'State',
654
- value: 'hello',
655
- subHooks: [],
656
- });
657
- });
658
-
601
it('should support useId hook', () => {
602
function Foo(props) {
603
const id = React.unstable_useId();
packages/react-devtools-shared/src/backend/ReactSymbols.js
-3
@@ -40,9 +40,6 @@ export const LAZY_SYMBOL_STRING = 'Symbol(react.lazy)';
40
export const MEMO_NUMBER = 0xead3;
41
export const MEMO_SYMBOL_STRING = 'Symbol(react.memo)';
42
43
-export const OPAQUE_ID_NUMBER = 0xeae0;
44
-export const OPAQUE_ID_SYMBOL_STRING = 'Symbol(react.opaque.id)';
45
-
43
export const PORTAL_NUMBER = 0xeaca;
44
export const PORTAL_SYMBOL_STRING = 'Symbol(react.portal)';
45
packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js
-1109
@@ -17,8 +17,6 @@ let React;
17
let ReactDOM;
18
let ReactDOMServer;
19
let ReactTestUtils;
20
-let act;
21
-let Scheduler;
20
let useState;
21
let useReducer;
22
let useEffect;
@@ -30,7 +28,6 @@ let useImperativeHandle;
28
let useInsertionEffect;
29
let useLayoutEffect;
30
let useDebugValue;
33
-let useOpaqueIdentifier;
31
let forwardRef;
32
let yieldedValues;
33
let yieldValue;
@@ -44,8 +41,6 @@ function initModules() {
41
ReactDOM = require('react-dom');
42
ReactDOMServer = require('react-dom/server');
43
ReactTestUtils = require('react-dom/test-utils');
47
- Scheduler = require('scheduler');
48
- act = require('jest-react').act;
44
useState = React.useState;
45
useReducer = React.useReducer;
46
useEffect = React.useEffect;
@@ -57,7 +52,6 @@ function initModules() {
52
useImperativeHandle = React.useImperativeHandle;
53
useInsertionEffect = React.useInsertionEffect;
54
useLayoutEffect = React.useLayoutEffect;
60
- useOpaqueIdentifier = React.unstable_useOpaqueIdentifier;
55
forwardRef = React.forwardRef;
56
57
yieldedValues = [];
@@ -83,9 +77,6 @@ const {
77
itRenders,
78
itThrowsWhenRendering,
79
serverRender,
86
- streamRender,
87
- clientCleanRender,
88
- clientRenderOnServerString,
80
} = ReactDOMServerIntegrationUtils(initModules);
81
82
describe('ReactDOMServerHooks', () => {
@@ -910,1104 +901,4 @@ describe('ReactDOMServerHooks', () => {
901
);
902
expect(container.children[0].textContent).toEqual('0');
903
});
913
-
914
- describe('useOpaqueIdentifier', () => {
915
- it('generates unique ids for server string render', async () => {
916
- function App(props) {
917
- const idOne = useOpaqueIdentifier();
918
- const idTwo = useOpaqueIdentifier();
919
- return (
920
- <div>
921
- <div aria-labelledby={idOne} />
922
- <div id={idOne} />
923
- <span aria-labelledby={idTwo} />
924
- <span id={idTwo} />
925
- </div>
926
- );
927
- }
928
-
929
- const domNode = await serverRender(<App />);
930
- expect(domNode.children.length).toEqual(4);
931
- expect(domNode.children[0].getAttribute('aria-labelledby')).toEqual(
932
- domNode.children[1].getAttribute('id'),
933
- );
934
- expect(domNode.children[2].getAttribute('aria-labelledby')).toEqual(
935
- domNode.children[3].getAttribute('id'),
936
- );
937
- expect(domNode.children[0].getAttribute('aria-labelledby')).not.toEqual(
938
- domNode.children[2].getAttribute('aria-labelledby'),
939
- );
940
- expect(
941
- domNode.children[0].getAttribute('aria-labelledby'),
942
- ).not.toBeNull();
943
- expect(
944
- domNode.children[2].getAttribute('aria-labelledby'),
945
- ).not.toBeNull();
946
- });
947
-
948
- it('generates unique ids for server stream render', async () => {
949
- function App(props) {
950
- const idOne = useOpaqueIdentifier();
951
- const idTwo = useOpaqueIdentifier();
952
- return (
953
- <div>
954
- <div aria-labelledby={idOne} />
955
- <div id={idOne} />
956
- <span aria-labelledby={idTwo} />
957
- <span id={idTwo} />
958
- </div>
959
- );
960
- }
961
-
962
- const domNode = await streamRender(<App />);
963
- expect(domNode.children.length).toEqual(4);
964
- expect(domNode.children[0].getAttribute('aria-labelledby')).toEqual(
965
- domNode.children[1].getAttribute('id'),
966
- );
967
- expect(domNode.children[2].getAttribute('aria-labelledby')).toEqual(
968
- domNode.children[3].getAttribute('id'),
969
- );
970
- expect(domNode.children[0].getAttribute('aria-labelledby')).not.toEqual(
971
- domNode.children[2].getAttribute('aria-labelledby'),
972
- );
973
- expect(
974
- domNode.children[0].getAttribute('aria-labelledby'),
975
- ).not.toBeNull();
976
- expect(
977
- domNode.children[2].getAttribute('aria-labelledby'),
978
- ).not.toBeNull();
979
- });
980
-
981
- it('generates unique ids for client render', async () => {
982
- function App(props) {
983
- const idOne = useOpaqueIdentifier();
984
- const idTwo = useOpaqueIdentifier();
985
- return (
986
- <div>
987
- <div aria-labelledby={idOne} />
988
- <div id={idOne} />
989
- <span aria-labelledby={idTwo} />
990
- <span id={idTwo} />
991
- </div>
992
- );
993
- }
994
-
995
- const domNode = await clientCleanRender(<App />);
996
- expect(domNode.children.length).toEqual(4);
997
- expect(domNode.children[0].getAttribute('aria-labelledby')).toEqual(
998
- domNode.children[1].getAttribute('id'),
999
- );
1000
- expect(domNode.children[2].getAttribute('aria-labelledby')).toEqual(
1001
- domNode.children[3].getAttribute('id'),
1002
- );
1003
- expect(domNode.children[0].getAttribute('aria-labelledby')).not.toEqual(
1004
- domNode.children[2].getAttribute('aria-labelledby'),
1005
- );
1006
- expect(
1007
- domNode.children[0].getAttribute('aria-labelledby'),
1008
- ).not.toBeNull();
1009
- expect(
1010
- domNode.children[2].getAttribute('aria-labelledby'),
1011
- ).not.toBeNull();
1012
- });
1013
-
1014
- it('generates unique ids for client render on good server markup', async () => {
1015
- function App(props) {
1016
- const idOne = useOpaqueIdentifier();
1017
- const idTwo = useOpaqueIdentifier();
1018
- return (
1019
- <div>
1020
- <div aria-labelledby={idOne} />
1021
- <div id={idOne} />
1022
- <span aria-labelledby={idTwo} />
1023
- <span id={idTwo} />
1024
- </div>
1025
- );
1026
- }
1027
-
1028
- const domNode = await clientRenderOnServerString(<App />);
1029
- expect(domNode.children.length).toEqual(4);
1030
- expect(domNode.children[0].getAttribute('aria-labelledby')).toEqual(
1031
- domNode.children[1].getAttribute('id'),
1032
- );
1033
- expect(domNode.children[2].getAttribute('aria-labelledby')).toEqual(
1034
- domNode.children[3].getAttribute('id'),
1035
- );
1036
- expect(domNode.children[0].getAttribute('aria-labelledby')).not.toEqual(
1037
- domNode.children[2].getAttribute('aria-labelledby'),
1038
- );
1039
- expect(
1040
- domNode.children[0].getAttribute('aria-labelledby'),
1041
- ).not.toBeNull();
1042
- expect(
1043
- domNode.children[2].getAttribute('aria-labelledby'),
1044
- ).not.toBeNull();
1045
- });
1046
-
1047
- it('useOpaqueIdentifier does not change id even if the component updates during client render', async () => {
1048
- let _setShowId;
1049
- function App() {
1050
- const id = useOpaqueIdentifier();
1051
- const [showId, setShowId] = useState(false);
1052
- _setShowId = setShowId;
1053
- return (
1054
- <div>
1055
- <div aria-labelledby={id} />
1056
- {showId && <div id={id} />}
1057
- </div>
1058
- );
1059
- }
1060
-
1061
- const domNode = await clientCleanRender(<App />);
1062
- const oldClientId = domNode.children[0].getAttribute('aria-labelledby');
1063
-
1064
- expect(domNode.children.length).toEqual(1);
1065
- expect(oldClientId).not.toBeNull();
1066
-
1067
- await act(async () => _setShowId(true));
1068
-
1069
- expect(domNode.children.length).toEqual(2);
1070
- expect(domNode.children[0].getAttribute('aria-labelledby')).toEqual(
1071
- domNode.children[1].getAttribute('id'),
1072
- );
1073
- expect(domNode.children[0].getAttribute('aria-labelledby')).toEqual(
1074
- oldClientId,
1075
- );
1076
- });
1077
-
1078
- it('useOpaqueIdentifier identifierPrefix works for server renderer and does not clash', async () => {
1079
- function ChildTwo({id}) {
1080
- return <div id={id}>Child Three</div>;
1081
- }
1082
- function App() {
1083
- const id = useOpaqueIdentifier();
1084
- const idTwo = useOpaqueIdentifier();
1085
-
1086
- return (
1087
- <div>
1088
- <div aria-labelledby={id}>Child One</div>
1089
- <ChildTwo id={id} />
1090
- <div aria-labelledby={idTwo}>Child Three</div>
1091
- <div id={idTwo}>Child Four</div>
1092
- </div>
1093
- );
1094
- }
1095
-
1096
- const containerOne = document.createElement('div');
1097
- document.body.append(containerOne);
1098
-
1099
- containerOne.innerHTML = ReactDOMServer.renderToString(<App />, {
1100
- identifierPrefix: 'one',
1101
- });
1102
-
1103
- const containerTwo = document.createElement('div');
1104
- document.body.append(containerTwo);
1105
-
1106
- containerTwo.innerHTML = ReactDOMServer.renderToString(<App />, {
1107
- identifierPrefix: 'two',
1108
- });
1109
-
1110
- expect(document.body.children.length).toEqual(2);
1111
- const childOne = document.body.children[0];
1112
- const childTwo = document.body.children[1];
1113
-
1114
- expect(
1115
- childOne.children[0].children[0].getAttribute('aria-labelledby'),
1116
- ).toEqual(childOne.children[0].children[1].getAttribute('id'));
1117
- expect(
1118
- childOne.children[0].children[2].getAttribute('aria-labelledby'),
1119
- ).toEqual(childOne.children[0].children[3].getAttribute('id'));
1120
-
1121
- expect(
1122
- childOne.children[0].children[0].getAttribute('aria-labelledby'),
1123
- ).not.toEqual(
1124
- childOne.children[0].children[2].getAttribute('aria-labelledby'),
1125
- );
1126
-
1127
- expect(
1128
- childOne.children[0].children[0]
1129
- .getAttribute('aria-labelledby')
1130
- .startsWith('one'),
1131
- ).toBe(true);
1132
- expect(
1133
- childOne.children[0].children[2]
1134
- .getAttribute('aria-labelledby')
1135
- .includes('one'),
1136
- ).toBe(true);
1137
-
1138
- expect(
1139
- childTwo.children[0].children[0].getAttribute('aria-labelledby'),
1140
- ).toEqual(childTwo.children[0].children[1].getAttribute('id'));
1141
- expect(
1142
- childTwo.children[0].children[2].getAttribute('aria-labelledby'),
1143
- ).toEqual(childTwo.children[0].children[3].getAttribute('id'));
1144
-
1145
- expect(
1146
- childTwo.children[0].children[0].getAttribute('aria-labelledby'),
1147
- ).not.toEqual(
1148
- childTwo.children[0].children[2].getAttribute('aria-labelledby'),
1149
- );
1150
-
1151
- expect(
1152
- childTwo.children[0].children[0]
1153
- .getAttribute('aria-labelledby')
1154
- .startsWith('two'),
1155
- ).toBe(true);
1156
- expect(
1157
- childTwo.children[0].children[2]
1158
- .getAttribute('aria-labelledby')
1159
- .startsWith('two'),
1160
- ).toBe(true);
1161
- });
1162
-
1163
- it('useOpaqueIdentifier identifierPrefix works for multiple reads on a streaming server renderer', async () => {
1164
- function ChildTwo() {
1165
- const id = useOpaqueIdentifier();
1166
-
1167
- return <div id={id}>Child Two</div>;
1168
- }
1169
-
1170
- function App() {
1171
- const id = useOpaqueIdentifier();
1172
-
1173
- return (
1174
- <>
1175
- <div id={id}>Child One</div>
1176
- <ChildTwo />
1177
- <div aria-labelledby={id}>Aria One</div>
1178
- </>
1179
- );
1180
- }
1181
-
1182
- const container = document.createElement('div');
1183
- document.body.append(container);
1184
-
1185
- const streamOne = ReactDOMServer.renderToNodeStream(<App />, {
1186
- identifierPrefix: 'one',
1187
- }).setEncoding('utf8');
1188
- const streamTwo = ReactDOMServer.renderToNodeStream(<App />, {
1189
- identifierPrefix: 'two',
1190
- }).setEncoding('utf8');
1191
-
1192
- const streamOneIsDone = new Promise((resolve, reject) => {
1193
- streamOne.on('end', () => resolve());
1194
- streamOne.on('error', e => reject(e));
1195
- });
1196
- const streamTwoIsDone = new Promise((resolve, reject) => {
1197
- streamTwo.on('end', () => resolve());
1198
- streamTwo.on('error', e => reject(e));
1199
- });
1200
-
1201
- const containerOne = document.createElement('div');
1202
- const containerTwo = document.createElement('div');
1203
-
1204
- streamOne._read(10);
1205
- streamTwo._read(10);
1206
-
1207
- containerOne.innerHTML = streamOne.read();
1208
- containerTwo.innerHTML = streamTwo.read();
1209
-
1210
- expect(containerOne.children[0].getAttribute('id')).not.toEqual(
1211
- containerOne.children[1].getAttribute('id'),
1212
- );
1213
- expect(containerTwo.children[0].getAttribute('id')).not.toEqual(
1214
- containerTwo.children[1].getAttribute('id'),
1215
- );
1216
- expect(containerOne.children[0].getAttribute('id')).not.toEqual(
1217
- containerTwo.children[0].getAttribute('id'),
1218
- );
1219
- expect(containerOne.children[0].getAttribute('id').includes('one')).toBe(
1220
- true,
1221
- );
1222
- expect(containerOne.children[1].getAttribute('id').includes('one')).toBe(
1223
- true,
1224
- );
1225
- expect(containerTwo.children[0].getAttribute('id').includes('two')).toBe(
1226
- true,
1227
- );
1228
- expect(containerTwo.children[1].getAttribute('id').includes('two')).toBe(
1229
- true,
1230
- );
1231
-
1232
- expect(containerOne.children[1].getAttribute('id')).not.toEqual(
1233
- containerTwo.children[1].getAttribute('id'),
1234
- );
1235
- expect(containerOne.children[0].getAttribute('id')).toEqual(
1236
- containerOne.children[2].getAttribute('aria-labelledby'),
1237
- );
1238
- expect(containerTwo.children[0].getAttribute('id')).toEqual(
1239
- containerTwo.children[2].getAttribute('aria-labelledby'),
1240
- );
1241
-
1242
- // Exhaust the rest of the stream
1243
- class Sink extends require('stream').Writable {
1244
- _write(chunk, encoding, done) {
1245
- done();
1246
- }
1247
- }
1248
- streamOne.pipe(new Sink());
1249
- streamTwo.pipe(new Sink());
1250
-
1251
- await Promise.all([streamOneIsDone, streamTwoIsDone]);
1252
- });
1253
-
1254
- it('useOpaqueIdentifier: IDs match when, after hydration, a new component that uses the ID is rendered', async () => {
1255
- let _setShowDiv;
1256
- function App() {
1257
- const id = useOpaqueIdentifier();
1258
- const [showDiv, setShowDiv] = useState(false);
1259
- _setShowDiv = setShowDiv;
1260
-
1261
- return (
1262
- <div>
1263
- <div id={id}>Child One</div>
1264
- {showDiv && <div id={id}>Child Two</div>}
1265
- </div>
1266
- );
1267
- }
1268
-
1269
- const container = document.createElement('div');
1270
- document.body.append(container);
1271
-
1272
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1273
- const root = ReactDOM.createRoot(container, {hydrate: true});
1274
- root.render(<App />);
1275
- Scheduler.unstable_flushAll();
1276
- jest.runAllTimers();
1277
-
1278
- expect(container.children[0].children.length).toEqual(1);
1279
- const oldServerId = container.children[0].children[0].getAttribute('id');
1280
- expect(oldServerId).not.toBeNull();
1281
-
1282
- await act(async () => {
1283
- _setShowDiv(true);
1284
- });
1285
- expect(container.children[0].children.length).toEqual(2);
1286
- expect(container.children[0].children[0].getAttribute('id')).toEqual(
1287
- container.children[0].children[1].getAttribute('id'),
1288
- );
1289
- expect(container.children[0].children[0].getAttribute('id')).not.toEqual(
1290
- oldServerId,
1291
- );
1292
- expect(
1293
- container.children[0].children[0].getAttribute('id'),
1294
- ).not.toBeNull();
1295
- });
1296
-
1297
- it('useOpaqueIdentifier: IDs match when, after hydration, a new component that uses the ID is rendered for legacy', async () => {
1298
- let _setShowDiv;
1299
- function App() {
1300
- const id = useOpaqueIdentifier();
1301
- const [showDiv, setShowDiv] = useState(false);
1302
- _setShowDiv = setShowDiv;
1303
-
1304
- return (
1305
- <div>
1306
- <div id={id}>Child One</div>
1307
- {showDiv && <div id={id}>Child Two</div>}
1308
- </div>
1309
- );
1310
- }
1311
-
1312
- const container = document.createElement('div');
1313
- document.body.append(container);
1314
-
1315
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1316
- ReactDOM.hydrate(<App />, container);
1317
-
1318
- expect(container.children[0].children.length).toEqual(1);
1319
- const oldServerId = container.children[0].children[0].getAttribute('id');
1320
- expect(oldServerId).not.toBeNull();
1321
-
1322
- await act(async () => {
1323
- _setShowDiv(true);
1324
- });
1325
- expect(container.children[0].children.length).toEqual(2);
1326
- expect(container.children[0].children[0].getAttribute('id')).toEqual(
1327
- container.children[0].children[1].getAttribute('id'),
1328
- );
1329
- expect(container.children[0].children[0].getAttribute('id')).not.toEqual(
1330
- oldServerId,
1331
- );
1332
- expect(
1333
- container.children[0].children[0].getAttribute('id'),
1334
- ).not.toBeNull();
1335
- });
1336
-
1337
- it('useOpaqueIdentifier: ID is not used during hydration but is used in an update', async () => {
1338
- let _setShow;
1339
- function App({unused}) {
1340
- Scheduler.unstable_yieldValue('App');
1341
- const id = useOpaqueIdentifier();
1342
- const [show, setShow] = useState(false);
1343
- _setShow = setShow;
1344
- return (
1345
- <div>
1346
- <span id={show ? id : null}>{'Child One'}</span>
1347
- </div>
1348
- );
1349
- }
1350
-
1351
- const container = document.createElement('div');
1352
- document.body.append(container);
1353
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1354
- const root = ReactDOM.createRoot(container, {hydrate: true});
1355
- act(() => {
1356
- root.render(<App />);
1357
- });
1358
- expect(Scheduler).toHaveYielded(['App', 'App']);
1359
- // The ID goes from not being used to being added to the page
1360
- act(() => {
1361
- _setShow(true);
1362
- });
1363
- expect(Scheduler).toHaveYielded(['App', 'App']);
1364
- expect(
1365
- container.getElementsByTagName('span')[0].getAttribute('id'),
1366
- ).not.toBeNull();
1367
- });
1368
-
1369
- it('useOpaqueIdentifier: ID is not used during hydration but is used in an update in legacy', async () => {
1370
- let _setShow;
1371
- function App({unused}) {
1372
- Scheduler.unstable_yieldValue('App');
1373
- const id = useOpaqueIdentifier();
1374
- const [show, setShow] = useState(false);
1375
- _setShow = setShow;
1376
- return (
1377
- <div>
1378
- <span id={show ? id : null}>{'Child One'}</span>
1379
- </div>
1380
- );
1381
- }
1382
-
1383
- const container = document.createElement('div');
1384
- document.body.append(container);
1385
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1386
- ReactDOM.hydrate(<App />, container);
1387
- expect(Scheduler).toHaveYielded(['App', 'App']);
1388
- // The ID goes from not being used to being added to the page
1389
- act(() => {
1390
- _setShow(true);
1391
- });
1392
- expect(Scheduler).toHaveYielded(['App']);
1393
- expect(
1394
- container.getElementsByTagName('span')[0].getAttribute('id'),
1395
- ).not.toBeNull();
1396
- });
1397
-
1398
- it('useOpaqueIdentifier: flushSync', async () => {
1399
- let _setShow;
1400
- function App() {
1401
- const id = useOpaqueIdentifier();
1402
- const [show, setShow] = useState(false);
1403
- _setShow = setShow;
1404
- return (
1405
- <div>
1406
- <span id={show ? id : null}>{'Child One'}</span>
1407
- </div>
1408
- );
1409
- }
1410
-
1411
- const container = document.createElement('div');
1412
- document.body.append(container);
1413
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1414
- const root = ReactDOM.createRoot(container, {hydrate: true});
1415
- act(() => {
1416
- root.render(<App />);
1417
- });
1418
-
1419
- // The ID goes from not being used to being added to the page
1420
- act(() => {
1421
- ReactDOM.flushSync(() => {
1422
- _setShow(true);
1423
- });
1424
- });
1425
- expect(
1426
- container.getElementsByTagName('span')[0].getAttribute('id'),
1427
- ).not.toBeNull();
1428
- });
1429
-
1430
- it('useOpaqueIdentifier: children with id hydrates before other children if ID updates', async () => {
1431
- let _setShow;
1432
-
1433
- const child1Ref = React.createRef();
1434
- const childWithIDRef = React.createRef();
1435
- const setShowRef = React.createRef();
1436
-
1437
- // RENAME THESE
1438
- function Child1() {
1439
- Scheduler.unstable_yieldValue('Child One');
1440
- return <span ref={child1Ref}>{'Child One'}</span>;
1441
- }
1442
-
1443
- function Child2() {
1444
- Scheduler.unstable_yieldValue('Child Two');
1445
- return <span>{'Child Two'}</span>;
1446
- }
1447
-
1448
- const Children = React.memo(function Children() {
1449
- return (
1450
- <React.Suspense fallback="Loading 1...">
1451
- <Child1 />
1452
- <Child2 />
1453
- </React.Suspense>
1454
- );
1455
- });
1456
-
1457
- function ChildWithID({parentID}) {
1458
- Scheduler.unstable_yieldValue('Child with ID');
1459
- return (
1460
- <span id={parentID} ref={childWithIDRef}>
1461
- {'Child with ID'}
1462
- </span>
1463
- );
1464
- }
1465
-
1466
- const ChildrenWithID = React.memo(function ChildrenWithID({parentID}) {
1467
- return (
1468
- <React.Suspense fallback="Loading 2...">
1469
- <ChildWithID parentID={parentID} />
1470
- </React.Suspense>
1471
- );
1472
- });
1473
-
1474
- function App() {
1475
- const id = useOpaqueIdentifier();
1476
- const [show, setShow] = useState(false);
1477
- _setShow = setShow;
1478
- return (
1479
- <div>
1480
- <Children />
1481
- <ChildrenWithID parentID={id} />
1482
- {show && (
1483
- <span aria-labelledby={id} ref={setShowRef}>
1484
- {'Child Three'}
1485
- </span>
1486
- )}
1487
- </div>
1488
- );
1489
- }
1490
-
1491
- const container = document.createElement('div');
1492
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1493
- expect(Scheduler).toHaveYielded([
1494
- 'Child One',
1495
- 'Child Two',
1496
- 'Child with ID',
1497
- ]);
1498
- expect(container.textContent).toEqual('Child OneChild TwoChild with ID');
1499
-
1500
- const serverId = container
1501
- .getElementsByTagName('span')[2]
1502
- .getAttribute('id');
1503
- expect(serverId).not.toBeNull();
1504
-
1505
- const root = ReactDOM.createRoot(container, {hydrate: true});
1506
- root.render(<App show={false} />);
1507
- expect(Scheduler).toHaveYielded([]);
1508
-
1509
- //Hydrate just child one before updating state
1510
- expect(Scheduler).toFlushAndYieldThrough(['Child One']);
1511
- expect(child1Ref.current).toBe(null);
1512
- expect(Scheduler).toHaveYielded([]);
1513
-
1514
- act(() => {
1515
- _setShow(true);
1516
-
1517
- // State update should trigger the ID to update, which changes the props
1518
- // of ChildWithID. This should cause ChildWithID to hydrate before Children
1519
-
1520
- expect(Scheduler).toFlushAndYieldThrough([
1521
- 'Child with ID',
1522
- // Fallbacks are immediately committed in TestUtils version
1523
- // of act
1524
- // 'Child with ID',
1525
- // 'Child with ID',
1526
- 'Child One',
1527
- 'Child Two',
1528
- ]);
1529
-
1530
- expect(child1Ref.current).toBe(null);
1531
- expect(childWithIDRef.current).toEqual(
1532
- container.getElementsByTagName('span')[2],
1533
- );
1534
-
1535
- expect(setShowRef.current).toEqual(
1536
- container.getElementsByTagName('span')[3],
1537
- );
1538
-
1539
- expect(childWithIDRef.current.getAttribute('id')).toEqual(
1540
- setShowRef.current.getAttribute('aria-labelledby'),
1541
- );
1542
- expect(childWithIDRef.current.getAttribute('id')).not.toEqual(serverId);
1543
- });
1544
-
1545
- // Children hydrates after ChildWithID
1546
- expect(child1Ref.current).toBe(container.getElementsByTagName('span')[0]);
1547
-
1548
- Scheduler.unstable_flushAll();
1549
-
1550
- expect(Scheduler).toHaveYielded([]);
1551
- });
1552
-
1553
- it('useOpaqueIdentifier: IDs match when part of the DOM tree is server rendered and part is client rendered', async () => {
1554
- let suspend = true;
1555
- let resolve;
1556
- const promise = new Promise(resolvePromise => (resolve = resolvePromise));
1557
-
1558
- function Child({text}) {
1559
- if (suspend) {
1560
- throw promise;
1561
- } else {
1562
- return text;
1563
- }
1564
- }
1565
-
1566
- function RenderedChild() {
1567
- useEffect(() => {
1568
- Scheduler.unstable_yieldValue('Child did commit');
1569
- });
1570
- return null;
1571
- }
1572
-
1573
- function App() {
1574
- const id = useOpaqueIdentifier();
1575
- useEffect(() => {
1576
- Scheduler.unstable_yieldValue('Did commit');
1577
- });
1578
- return (
1579
- <div>
1580
- <div id={id}>Child One</div>
1581
- <RenderedChild />
1582
- <React.Suspense fallback={'Fallback'}>
1583
- <div id={id}>
1584
- <Child text="Child Two" />
1585
- </div>
1586
- </React.Suspense>
1587
- </div>
1588
- );
1589
- }
1590
-
1591
- const container = document.createElement('div');
1592
- document.body.appendChild(container);
1593
-
1594
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1595
-
1596
- suspend = true;
1597
- const root = ReactDOM.createRoot(container, {hydrate: true});
1598
- await act(async () => {
1599
- root.render(<App />);
1600
- });
1601
- jest.runAllTimers();
1602
- expect(Scheduler).toHaveYielded(['Child did commit', 'Did commit']);
1603
- expect(Scheduler).toFlushAndYield([]);
1604
-
1605
- const serverId = container.children[0].children[0].getAttribute('id');
1606
- expect(container.children[0].children.length).toEqual(1);
1607
- expect(
1608
- container.children[0].children[0].getAttribute('id'),
1609
- ).not.toBeNull();
1610
-
1611
- await act(async () => {
1612
- suspend = false;
1613
- resolve();
1614
- await promise;
1615
- });
1616
-
1617
- expect(Scheduler).toHaveYielded(['Child did commit', 'Did commit']);
1618
- expect(Scheduler).toFlushAndYield([]);
1619
- jest.runAllTimers();
1620
-
1621
- expect(container.children[0].children.length).toEqual(2);
1622
- expect(container.children[0].children[0].getAttribute('id')).toEqual(
1623
- container.children[0].children[1].getAttribute('id'),
1624
- );
1625
- expect(container.children[0].children[0].getAttribute('id')).not.toEqual(
1626
- serverId,
1627
- );
1628
- expect(
1629
- container.children[0].children[0].getAttribute('id'),
1630
- ).not.toBeNull();
1631
- });
1632
-
1633
- it('useOpaqueIdentifier warn when there is a hydration error', async () => {
1634
- function Child({appId}) {
1635
- return <div aria-labelledby={appId} />;
1636
- }
1637
- function App() {
1638
- const id = useOpaqueIdentifier();
1639
- return <Child appId={id} />;
1640
- }
1641
-
1642
- const container = document.createElement('div');
1643
- document.body.appendChild(container);
1644
-
1645
- // This is the wrong HTML string
1646
- container.innerHTML = '<span></span>';
1647
- ReactDOM.createRoot(container, {hydrate: true}).render(<App />);
1648
- expect(() => Scheduler.unstable_flushAll()).toErrorDev(
1649
- [
1650
- 'Warning: An error occurred during hydration. The server HTML was replaced with client content in <div>.',
1651
- 'Warning: Expected server HTML to contain a matching <div> in <div>.',
1652
- ],
1653
- {withoutStack: 1},
1654
- );
1655
- });
1656
-
1657
- it('useOpaqueIdentifier: IDs match when part of the DOM tree is server rendered and part is client rendered', async () => {
1658
- let suspend = true;
1659
-
1660
- function Child({text}) {
1661
- if (suspend) {
1662
- throw new Promise(() => {});
1663
- } else {
1664
- return text;
1665
- }
1666
- }
1667
-
1668
- function RenderedChild() {
1669
- useEffect(() => {
1670
- Scheduler.unstable_yieldValue('Child did commit');
1671
- });
1672
- return null;
1673
- }
1674
-
1675
- function App() {
1676
- const id = useOpaqueIdentifier();
1677
- useEffect(() => {
1678
- Scheduler.unstable_yieldValue('Did commit');
1679
- });
1680
- return (
1681
- <div>
1682
- <div id={id}>Child One</div>
1683
- <RenderedChild />
1684
- <React.Suspense fallback={'Fallback'}>
1685
- <div id={id}>
1686
- <Child text="Child Two" />
1687
- </div>
1688
- </React.Suspense>
1689
- </div>
1690
- );
1691
- }
1692
-
1693
- const container = document.createElement('div');
1694
- document.body.appendChild(container);
1695
-
1696
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1697
-
1698
- suspend = false;
1699
- const root = ReactDOM.createRoot(container, {hydrate: true});
1700
- await act(async () => {
1701
- root.render(<App />);
1702
- });
1703
- jest.runAllTimers();
1704
- expect(Scheduler).toHaveYielded([
1705
- 'Child did commit',
1706
- 'Did commit',
1707
- 'Child did commit',
1708
- 'Did commit',
1709
- ]);
1710
- expect(Scheduler).toFlushAndYield([]);
1711
-
1712
- expect(container.children[0].children.length).toEqual(2);
1713
- expect(container.children[0].children[0].getAttribute('id')).toEqual(
1714
- container.children[0].children[1].getAttribute('id'),
1715
- );
1716
- expect(
1717
- container.children[0].children[0].getAttribute('id'),
1718
- ).not.toBeNull();
1719
- });
1720
-
1721
- it('useOpaqueIdentifier warn when there is a hydration error', async () => {
1722
- function Child({appId}) {
1723
- return <div aria-labelledby={appId} />;
1724
- }
1725
- function App() {
1726
- const id = useOpaqueIdentifier();
1727
- return <Child appId={id} />;
1728
- }
1729
-
1730
- const container = document.createElement('div');
1731
- document.body.appendChild(container);
1732
-
1733
- // This is the wrong HTML string
1734
- container.innerHTML = '<span></span>';
1735
- ReactDOM.createRoot(container, {hydrate: true}).render(<App />);
1736
- expect(() => Scheduler.unstable_flushAll()).toErrorDev(
1737
- [
1738
- 'Warning: An error occurred during hydration. The server HTML was replaced with client content in <div>.',
1739
- 'Warning: Expected server HTML to contain a matching <div> in <div>.',
1740
- ],
1741
- {withoutStack: 1},
1742
- );
1743
- });
1744
-
1745
- it('useOpaqueIdentifier warns when there is a hydration error and we are using ID as a string', async () => {
1746
- function Child({appId}) {
1747
- return <div aria-labelledby={String(appId)} />;
1748
- }
1749
- function App() {
1750
- const id = useOpaqueIdentifier();
1751
- return <Child appId={id} />;
1752
- }
1753
-
1754
- const container = document.createElement('div');
1755
- document.body.appendChild(container);
1756
-
1757
- // This is the wrong HTML string
1758
- container.innerHTML = '<span></span>';
1759
- ReactDOM.createRoot(container, {hydrate: true}).render(<App />);
1760
- expect(() => Scheduler.unstable_flushAll()).toErrorDev(
1761
- [
1762
- 'Warning: The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. Do not read the value directly.',
1763
- 'Warning: An error occurred during hydration. The server HTML was replaced with client content in <div>.',
1764
- ],
1765
- {withoutStack: 1},
1766
- );
1767
- });
1768
-
1769
- it('useOpaqueIdentifier warns when there is a hydration error and we are using ID as a string', async () => {
1770
- function Child({appId}) {
1771
- return <div aria-labelledby={String(appId)} />;
1772
- }
1773
- function App() {
1774
- const id = useOpaqueIdentifier();
1775
- return <Child appId={id} />;
1776
- }
1777
-
1778
- const container = document.createElement('div');
1779
- document.body.appendChild(container);
1780
-
1781
- // This is the wrong HTML string
1782
- container.innerHTML = '<span></span>';
1783
- ReactDOM.createRoot(container, {hydrate: true}).render(<App />);
1784
- expect(() => Scheduler.unstable_flushAll()).toErrorDev(
1785
- [
1786
- 'Warning: The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. Do not read the value directly.',
1787
- 'Warning: An error occurred during hydration. The server HTML was replaced with client content in <div>.',
1788
- ],
1789
- {withoutStack: 1},
1790
- );
1791
- });
1792
-
1793
- it('useOpaqueIdentifier warns if you try to use the result as a string in a child component', async () => {
1794
- function Child({appId}) {
1795
- return <div aria-labelledby={String(appId)} />;
1796
- }
1797
- function App() {
1798
- const id = useOpaqueIdentifier();
1799
- return <Child appId={id} />;
1800
- }
1801
-
1802
- const container = document.createElement('div');
1803
- document.body.appendChild(container);
1804
-
1805
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1806
- ReactDOM.createRoot(container, {hydrate: true}).render(<App />);
1807
- expect(() => Scheduler.unstable_flushAll()).toErrorDev(
1808
- [
1809
- 'Warning: The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. Do not read the value directly.',
1810
- 'Warning: An error occurred during hydration. The server HTML was replaced with client content in <div>.',
1811
- ],
1812
- {withoutStack: 1},
1813
- );
1814
- });
1815
-
1816
- it('useOpaqueIdentifier warns if you try to use the result as a string', async () => {
1817
- function App() {
1818
- const id = useOpaqueIdentifier();
1819
- return <div aria-labelledby={String(id)} />;
1820
- }
1821
-
1822
- const container = document.createElement('div');
1823
- document.body.appendChild(container);
1824
-
1825
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1826
- ReactDOM.createRoot(container, {hydrate: true}).render(<App />);
1827
- expect(() => Scheduler.unstable_flushAll()).toErrorDev(
1828
- [
1829
- 'Warning: The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. Do not read the value directly.',
1830
- 'Warning: An error occurred during hydration. The server HTML was replaced with client content in <div>.',
1831
- ],
1832
- {withoutStack: 1},
1833
- );
1834
- });
1835
-
1836
- it('useOpaqueIdentifier warns if you try to use the result as a string in a child component wrapped in a Suspense', async () => {
1837
- function Child({appId}) {
1838
- return <div aria-labelledby={String(appId)} />;
1839
- }
1840
- function App() {
1841
- const id = useOpaqueIdentifier();
1842
- return (
1843
- <React.Suspense fallback={null}>
1844
- <Child appId={id} />
1845
- </React.Suspense>
1846
- );
1847
- }
1848
-
1849
- const container = document.createElement('div');
1850
- document.body.appendChild(container);
1851
-
1852
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1853
-
1854
- ReactDOM.createRoot(container, {hydrate: true}).render(<App />);
1855
-
1856
- if (gate(flags => flags.deferRenderPhaseUpdateToNextBatch)) {
1857
- expect(() => Scheduler.unstable_flushAll()).toErrorDev([
1858
- 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
1859
- 'Do not read the value directly.',
1860
- ]);
1861
- } else {
1862
- // This error isn't surfaced to the user; only the warning is.
1863
- // The error is just the mechanism that restarts the render.
1864
- expect(() =>
1865
- expect(() => Scheduler.unstable_flushAll()).toThrow(
1866
- 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
1867
- 'Do not read the value directly.',
1868
- ),
1869
- ).toErrorDev([
1870
- 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
1871
- 'Do not read the value directly.',
1872
- ]);
1873
- }
1874
- });
1875
-
1876
- it('useOpaqueIdentifier warns if you try to add the result as a number in a child component wrapped in a Suspense', async () => {
1877
- function Child({appId}) {
1878
- return <div aria-labelledby={+appId} />;
1879
- }
1880
- function App() {
1881
- const [show] = useState(false);
1882
- const id = useOpaqueIdentifier();
1883
- return (
1884
- <React.Suspense fallback={null}>
1885
- {show && <div id={id} />}
1886
- <Child appId={id} />
1887
- </React.Suspense>
1888
- );
1889
- }
1890
-
1891
- const container = document.createElement('div');
1892
- document.body.appendChild(container);
1893
-
1894
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1895
-
1896
- ReactDOM.createRoot(container, {hydrate: true}).render(<App />);
1897
-
1898
- if (gate(flags => flags.deferRenderPhaseUpdateToNextBatch)) {
1899
- expect(() => Scheduler.unstable_flushAll()).toErrorDev([
1900
- 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
1901
- 'Do not read the value directly.',
1902
- ]);
1903
- } else {
1904
- // This error isn't surfaced to the user; only the warning is.
1905
- // The error is just the mechanism that restarts the render.
1906
- expect(() =>
1907
- expect(() => Scheduler.unstable_flushAll()).toThrow(
1908
- 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
1909
- 'Do not read the value directly.',
1910
- ),
1911
- ).toErrorDev([
1912
- 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
1913
- 'Do not read the value directly.',
1914
- ]);
1915
- }
1916
- });
1917
-
1918
- it('useOpaqueIdentifier with two opaque identifiers on the same page', () => {
1919
- let _setShow;
1920
-
1921
- function App() {
1922
- const id1 = useOpaqueIdentifier();
1923
- const id2 = useOpaqueIdentifier();
1924
- const [show, setShow] = useState(true);
1925
- _setShow = setShow;
1926
-
1927
- return (
1928
- <div>
1929
- <React.Suspense fallback={null}>
1930
- {show ? (
1931
- <span id={id1}>{'Child'}</span>
1932
- ) : (
1933
- <span id={id2}>{'Child'}</span>
1934
- )}
1935
- </React.Suspense>
1936
- <span aria-labelledby={id1}>{'test'}</span>
1937
- </div>
1938
- );
1939
- }
1940
-
1941
- const container = document.createElement('div');
1942
- document.body.appendChild(container);
1943
-
1944
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1945
-
1946
- const serverID = container
1947
- .getElementsByTagName('span')[0]
1948
- .getAttribute('id');
1949
- expect(serverID).not.toBeNull();
1950
- expect(
1951
- container
1952
- .getElementsByTagName('span')[1]
1953
- .getAttribute('aria-labelledby'),
1954
- ).toEqual(serverID);
1955
-
1956
- ReactDOM.createRoot(container, {hydrate: true}).render(<App />);
1957
- jest.runAllTimers();
1958
- expect(Scheduler).toHaveYielded([]);
1959
- expect(Scheduler).toFlushAndYield([]);
1960
-
1961
- act(() => {
1962
- _setShow(false);
1963
- });
1964
-
1965
- expect(
1966
- container
1967
- .getElementsByTagName('span')[1]
1968
- .getAttribute('aria-labelledby'),
1969
- ).toEqual(serverID);
1970
- expect(
1971
- container.getElementsByTagName('span')[0].getAttribute('id'),
1972
- ).not.toEqual(serverID);
1973
- expect(
1974
- container.getElementsByTagName('span')[0].getAttribute('id'),
1975
- ).not.toBeNull();
1976
- });
1977
-
1978
- it('useOpaqueIdentifier with multiple ids in nested components', async () => {
1979
- function DivWithId({id, children}) {
1980
- return <div id={id}>{children}</div>;
1981
- }
1982
-
1983
- let setShowMore;
1984
- function App() {
1985
- const outerId = useOpaqueIdentifier();
1986
- const innerId = useOpaqueIdentifier();
1987
- const [showMore, _setShowMore] = useState(false);
1988
- setShowMore = _setShowMore;
1989
- return showMore ? (
1990
- <DivWithId id={outerId}>
1991
- <DivWithId id={innerId} />
1992
- </DivWithId>
1993
- ) : null;
1994
- }
1995
-
1996
- const container = document.createElement('div');
1997
- container.innerHTML = ReactDOMServer.renderToString(<App />);
1998
-
1999
- await act(async () => {
2000
- ReactDOM.hydrateRoot(container, <App />);
2001
- });
2002
-
2003
- // Show additional content that wasn't part of the initial server-
2004
- // rendered repsonse.
2005
- await act(async () => {
2006
- setShowMore(true);
2007
- });
2008
- const [div1, div2] = container.getElementsByTagName('div');
2009
- expect(typeof div1.getAttribute('id')).toBe('string');
2010
- expect(typeof div2.getAttribute('id')).toBe('string');
2011
- });
2012
- });
904
});
packages/react-dom/src/client/DOMPropertyOperations.js
-8
@@ -21,7 +21,6 @@ import {
21
enableTrustedTypesIntegration,
22
} from 'shared/ReactFeatureFlags';
23
import {checkAttributeStringCoercion} from 'shared/CheckStringCoercion';
24
-import {isOpaqueHydratingObject} from './ReactDOMHostConfig';
24
25
import type {PropertyInfo} from '../shared/DOMProperty';
26
@@ -119,13 +118,6 @@ export function getValueForAttribute(
118
if (!isAttributeNameSafe(name)) {
119
return;
120
}
122
-
123
- // If the object is an opaque reference ID, it's expected that
124
- // the next prop is different than the server value, so just return
125
- // expected
126
- if (isOpaqueHydratingObject(expected)) {
127
- return expected;
128
- }
121
if (!node.hasAttribute(name)) {
122
return expected === undefined ? undefined : null;
123
}
packages/react-dom/src/client/ReactDOMComponent.js
-10
@@ -68,7 +68,6 @@ import possibleStandardNames from '../shared/possibleStandardNames';
68
import {validateProperties as validateARIAProperties} from '../shared/ReactDOMInvalidARIAHook';
69
import {validateProperties as validateInputProperties} from '../shared/ReactDOMNullInputValuePropHook';
70
import {validateProperties as validateUnknownProperties} from '../shared/ReactDOMUnknownPropertyHook';
71
-import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
71
72
import {enableTrustedTypesIntegration} from 'shared/ReactFeatureFlags';
73
import {
@@ -775,15 +774,6 @@ export function diffProperties(
774
// to update this element.
775
updatePayload = [];
776
}
778
- } else if (
779
- typeof nextProp === 'object' &&
780
- nextProp !== null &&
781
- nextProp.$$typeof === REACT_OPAQUE_ID_TYPE
782
- ) {
783
- // If we encounter useOpaqueReference's opaque object, this means we are hydrating.
784
- // In this case, call the opaque object's toString function which generates a new client
785
- // ID so client and server IDs match and throws to rerender.
786
- nextProp.toString();
777
} else {
778
// For any other property we always add it to the queue and then we
779
// filter it out using the allowed property list during the commit.
packages/react-dom/src/client/ReactDOMHostConfig.js
-45
@@ -59,7 +59,6 @@ import {
59
} from '../shared/HTMLNodeType';
60
import dangerousStyleValue from '../shared/dangerousStyleValue';
61
62
-import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
62
import {retryIfBlockedOn} from '../events/ReactDOMEventReplaying';
63
64
import {
@@ -124,13 +123,6 @@ export type TimeoutHandle = TimeoutID;
123
export type NoTimeout = -1;
124
export type RendererInspectionConfig = $ReadOnly<{||}>;
125
127
-export opaque type OpaqueIDType =
128
- | string
129
- | {
130
- toString: () => string | void,
131
- valueOf: () => string | void,
132
- };
133
-
126
type SelectionInformation = {|
127
focusedElem: null | HTMLElement,
128
selectionRange: mixed,
@@ -1089,43 +1081,6 @@ export function getInstanceFromNode(node: HTMLElement): null | Object {
1081
return getClosestInstanceFromNode(node) || null;
1082
}
1083
1092
-let clientId: number = 0;
1093
-export function makeClientId(): OpaqueIDType {
1094
- return 'r:' + (clientId++).toString(36);
1095
-}
1096
-
1097
-export function makeClientIdInDEV(warnOnAccessInDEV: () => void): OpaqueIDType {
1098
- const id = 'r:' + (clientId++).toString(36);
1099
- return {
1100
- toString() {
1101
- warnOnAccessInDEV();
1102
- return id;
1103
- },
1104
- valueOf() {
1105
- warnOnAccessInDEV();
1106
- return id;
1107
- },
1108
- };
1109
-}
1110
-
1111
-export function isOpaqueHydratingObject(value: mixed): boolean {
1112
- return (
1113
- value !== null &&
1114
- typeof value === 'object' &&
1115
- value.$$typeof === REACT_OPAQUE_ID_TYPE
1116
- );
1117
-}
1118
-
1119
-export function makeOpaqueHydratingObject(
1120
- attemptToReadValue: () => void,
1121
-): OpaqueIDType {
1122
- return {
1123
- $$typeof: REACT_OPAQUE_ID_TYPE,
1124
- toString: attemptToReadValue,
1125
- valueOf: attemptToReadValue,
1126
- };
1127
-}
1128
-
1084
export function preparePortalMount(portalInstance: Instance): void {
1085
listenToAllSupportedEvents(portalInstance);
1086
}
packages/react-dom/src/server/ReactDOMServerFormatConfig.js
-22
@@ -64,9 +64,7 @@ export type ResponseState = {
64
placeholderPrefix: PrecomputedChunk,
65
segmentPrefix: PrecomputedChunk,
66
boundaryPrefix: string,
67
- opaqueIdentifierPrefix: string,
67
nextSuspenseID: number,
69
- nextOpaqueID: number,
68
sentCompleteSegmentFunction: boolean,
69
sentCompleteBoundaryFunction: boolean,
70
sentClientRenderFunction: boolean, // We allow the legacy renderer to extend this object.
@@ -127,9 +125,7 @@ export function createResponseState(
125
placeholderPrefix: stringToPrecomputedChunk(idPrefix + 'P:'),
126
segmentPrefix: stringToPrecomputedChunk(idPrefix + 'S:'),
127
boundaryPrefix: idPrefix + 'B:',
130
- opaqueIdentifierPrefix: idPrefix + 'R:',
128
nextSuspenseID: 0,
132
- nextOpaqueID: 0,
129
sentCompleteSegmentFunction: false,
130
sentCompleteBoundaryFunction: false,
131
sentClientRenderFunction: false,
@@ -233,24 +229,6 @@ export function assignSuspenseBoundaryID(
229
);
230
}
231
236
-export type OpaqueIDType = string;
237
-
238
-export function makeServerID(
239
- responseState: null | ResponseState,
240
-): OpaqueIDType {
241
- if (responseState === null) {
242
- throw new Error(
243
- 'Invalid hook call. Hooks can only be called inside of the body of a function component.',
244
- );
245
- }
246
-
247
- // TODO: This is not deterministic since it's created during render.
248
- return (
249
- responseState.opaqueIdentifierPrefix +
250
- (responseState.nextOpaqueID++).toString(36)
251
- );
252
-}
253
-
232
function encodeHTMLTextNode(text: string): string {
233
return escapeTextForBrowser(text);
234
}
packages/react-dom/src/server/ReactDOMServerLegacyFormatConfig.js
-6
@@ -34,9 +34,7 @@ export type ResponseState = {
34
placeholderPrefix: PrecomputedChunk,
35
segmentPrefix: PrecomputedChunk,
36
boundaryPrefix: string,
37
- opaqueIdentifierPrefix: string,
37
nextSuspenseID: number,
39
- nextOpaqueID: number,
38
sentCompleteSegmentFunction: boolean,
39
sentCompleteBoundaryFunction: boolean,
40
sentClientRenderFunction: boolean,
@@ -56,9 +54,7 @@ export function createResponseState(
54
placeholderPrefix: responseState.placeholderPrefix,
55
segmentPrefix: responseState.segmentPrefix,
56
boundaryPrefix: responseState.boundaryPrefix,
59
- opaqueIdentifierPrefix: responseState.opaqueIdentifierPrefix,
57
nextSuspenseID: responseState.nextSuspenseID,
61
- nextOpaqueID: responseState.nextOpaqueID,
58
sentCompleteSegmentFunction: responseState.sentCompleteSegmentFunction,
59
sentCompleteBoundaryFunction: responseState.sentCompleteBoundaryFunction,
60
sentClientRenderFunction: responseState.sentClientRenderFunction,
@@ -77,14 +73,12 @@ export function createRootFormatContext(): FormatContext {
73
export type {
74
FormatContext,
75
SuspenseBoundaryID,
80
- OpaqueIDType,
76
} from './ReactDOMServerFormatConfig';
77
78
export {
79
getChildFormatContext,
80
UNINITIALIZED_SUSPENSE_BOUNDARY_ID,
81
assignSuspenseBoundaryID,
87
- makeServerID,
82
pushStartInstance,
83
pushEndInstance,
84
pushStartCompletedSuspenseBoundary,
packages/react-dom/src/server/ReactPartialRenderer.js
+1
-16
@@ -82,10 +82,6 @@ import {validateProperties as validateInputProperties} from '../shared/ReactDOMN
82
import {validateProperties as validateUnknownProperties} from '../shared/ReactDOMUnknownPropertyHook';
83
import hasOwnProperty from 'shared/hasOwnProperty';
84
85
-export type ServerOptions = {
86
- identifierPrefix?: string,
87
-};
88
-
85
// Based on reading the React.Children implementation. TODO: type this somewhere?
86
type ReactNode = string | number | ReactElement;
87
type FlatReactChildren = Array<null | ReactNode>;
@@ -784,14 +780,7 @@ class ReactDOMServerRenderer {
780
contextValueStack: Array<any>;
781
contextProviderStack: ?Array<ReactProvider<any>>; // DEV-only
782
787
- uniqueID: number;
788
- identifierPrefix: string;
789
-
790
- constructor(
791
- children: mixed,
792
- makeStaticMarkup: boolean,
793
- options?: ServerOptions,
794
- ) {
783
+ constructor(children: mixed, makeStaticMarkup: boolean) {
784
const flatChildren = flattenTopLevelChildren(children);
785
786
const topFrame: Frame = {
@@ -820,10 +809,6 @@ class ReactDOMServerRenderer {
809
this.contextStack = [];
810
this.contextValueStack = [];
811
823
- // useOpaqueIdentifier ID
824
- this.uniqueID = 0;
825
- this.identifierPrefix = (options && options.identifierPrefix) || '';
826
-
812
if (__DEV__) {
813
this.contextProviderStack = [];
814
}
packages/react-dom/src/server/ReactPartialRendererHooks.js
+1
-12
@@ -41,8 +41,6 @@ type Hook = {|
41
next: Hook | null,
42
|};
43
44
-type OpaqueIDType = string;
45
-
44
let currentlyRenderingComponent: Object | null = null;
45
let firstWorkInProgressHook: Hook | null = null;
46
let workInProgressHook: Hook | null = null;
@@ -511,15 +509,7 @@ function useTransition(): [boolean, (callback: () => void) => void] {
509
return [false, startTransition];
510
}
511
514
-function useOpaqueIdentifier(): OpaqueIDType {
515
- return (
516
- (currentPartialRenderer.identifierPrefix || '') +
517
- 'R:' +
518
- (currentPartialRenderer.uniqueID++).toString(36)
519
- );
520
-}
521
-
522
-function useId(): OpaqueIDType {
512
+function useId(): string {
513
throw new Error('Not implemented.');
514
}
515
@@ -552,7 +542,6 @@ export const Dispatcher: DispatcherType = {
542
useDebugValue: noop,
543
useDeferredValue,
544
useTransition,
555
- useOpaqueIdentifier,
545
useId,
546
// Subscriptions are not setup in a server environment.
547
useMutableSource,
packages/react-native-renderer/src/ReactFabricHostConfig.js
-20
@@ -84,8 +84,6 @@ export type UpdatePayload = Object;
84
export type TimeoutHandle = TimeoutID;
85
export type NoTimeout = -1;
86
87
-export type OpaqueIDType = void;
88
-
87
export type RendererInspectionConfig = $ReadOnly<{|
88
// Deprecated. Replaced with getInspectorDataForViewAtPoint.
89
getInspectorDataForViewTag?: (tag: number) => Object,
@@ -512,24 +510,6 @@ export function getInstanceFromNode(node: any) {
510
throw new Error('Not yet implemented.');
511
}
512
515
-export function isOpaqueHydratingObject(value: mixed): boolean {
516
- throw new Error('Not yet implemented');
517
-}
518
-
519
-export function makeOpaqueHydratingObject(
520
- attemptToReadValue: () => void,
521
-): OpaqueIDType {
522
- throw new Error('Not yet implemented.');
523
-}
524
-
525
-export function makeClientId(): OpaqueIDType {
526
- throw new Error('Not yet implemented');
527
-}
528
-
529
-export function makeClientIdInDEV(warnOnAccessInDEV: () => void): OpaqueIDType {
530
- throw new Error('Not yet implemented');
531
-}
532
-
513
export function beforeActiveInstanceBlur(internalInstanceHandle: Object) {
514
// noop
515
}
packages/react-native-renderer/src/ReactNativeHostConfig.js
-19
@@ -43,7 +43,6 @@ export type ChildSet = void; // Unused
43
44
export type TimeoutHandle = TimeoutID;
45
export type NoTimeout = -1;
46
-export type OpaqueIDType = void;
46
47
export type RendererInspectionConfig = $ReadOnly<{|
48
// Deprecated. Replaced with getInspectorDataForViewAtPoint.
@@ -499,24 +498,6 @@ export function getInstanceFromNode(node: any) {
498
throw new Error('Not yet implemented.');
499
}
500
502
-export function isOpaqueHydratingObject(value: mixed): boolean {
503
- throw new Error('Not yet implemented');
504
-}
505
-
506
-export function makeOpaqueHydratingObject(
507
- attemptToReadValue: () => void,
508
-): OpaqueIDType {
509
- throw new Error('Not yet implemented.');
510
-}
511
-
512
-export function makeClientId(): OpaqueIDType {
513
- throw new Error('Not yet implemented');
514
-}
515
-
516
-export function makeClientIdInDEV(warnOnAccessInDEV: () => void): OpaqueIDType {
517
- throw new Error('Not yet implemented');
518
-}
519
-
501
export function beforeActiveInstanceBlur(internalInstanceHandle: Object) {
502
// noop
503
}
packages/react-native-renderer/src/server/ReactNativeServerFormatConfig.js
-17
@@ -59,14 +59,12 @@ SUSPENSE_UPDATE_TO_CLIENT_RENDER[0] = SUSPENSE_UPDATE_TO_CLIENT_RENDER_TAG;
59
// Per response,
60
export type ResponseState = {
61
nextSuspenseID: number,
62
- nextOpaqueID: number,
62
};
63
64
// Allows us to keep track of what we've already written so we can refer back to it.
65
export function createResponseState(): ResponseState {
66
return {
67
nextSuspenseID: 0,
69
- nextOpaqueID: 0,
68
};
69
}
70
@@ -109,21 +107,6 @@ export function assignSuspenseBoundaryID(
107
return responseState.nextSuspenseID++;
108
}
109
112
-export type OpaqueIDType = number;
113
-
114
-export function makeServerID(
115
- responseState: null | ResponseState,
116
-): OpaqueIDType {
117
- if (responseState === null) {
118
- throw new Error(
119
- 'Invalid hook call. Hooks can only be called inside of the body of a function component.',
120
- );
121
- }
122
-
123
- // TODO: This is not deterministic since it's created during render.
124
- return responseState.nextOpaqueID++;
125
-}
126
-
110
const RAW_TEXT = stringToPrecomputedChunk('RCTRawText');
111
112
export function pushTextInstance(
packages/react-noop-renderer/src/ReactNoopServer.js
-6
@@ -53,8 +53,6 @@ type Destination = {
53
54
const POP = Buffer.from('/', 'utf8');
55
56
-let opaqueID = 0;
57
-
56
const ReactNoopServer = ReactFizzServer({
57
scheduleWork(callback: () => void) {
58
callback();
@@ -88,10 +86,6 @@ const ReactNoopServer = ReactFizzServer({
86
return {state: 'pending', children: []};
87
},
88
91
- makeServerID(): number {
92
- return opaqueID++;
93
- },
94
-
89
getChildFormatContext(): null {
90
return null;
91
},
packages/react-reconciler/src/ReactFiberHooks.new.js
-139
@@ -17,7 +17,6 @@ import type {Fiber, Dispatcher, HookType} from './ReactInternalTypes';
17
import type {Lanes, Lane} from './ReactFiberLane.new';
18
import type {HookFlags} from './ReactHookEffectTags';
19
import type {FiberRoot} from './ReactInternalTypes';
20
-import type {OpaqueIDType} from './ReactFiberHostConfig';
20
import type {Cache} from './ReactFiberCacheComponent.new';
21
import type {Flags} from './ReactFiberFlags';
22
@@ -95,18 +94,12 @@ import {
94
checkIfWorkInProgressReceivedUpdate,
95
} from './ReactFiberBeginWork.new';
96
import {getIsHydrating} from './ReactFiberHydrationContext.new';
98
-import {
99
- makeClientId,
100
- makeClientIdInDEV,
101
- makeOpaqueHydratingObject,
102
-} from './ReactFiberHostConfig';
97
import {
98
getWorkInProgressVersion,
99
markSourceAsDirty,
100
setWorkInProgressVersion,
101
warnAboutMultipleRenderersDEV,
102
} from './ReactMutableSource.new';
109
-import {getIsRendering} from './ReactCurrentFiber';
103
import {logStateUpdateScheduled} from './DebugTracing';
104
import {markStateUpdateScheduled} from './SchedulingProfiler';
105
import {createCache, CacheContext} from './ReactFiberCacheComponent.new';
@@ -139,10 +132,8 @@ export type UpdateQueue<S, A> = {|
132
|};
133
134
let didWarnAboutMismatchedHooksForComponent;
142
-let didWarnAboutUseOpaqueIdentifier;
135
let didWarnUncachedGetSnapshot;
136
if (__DEV__) {
145
- didWarnAboutUseOpaqueIdentifier = {};
137
didWarnAboutMismatchedHooksForComponent = new Set();
138
}
139
@@ -2045,94 +2036,6 @@ export function getIsUpdatingOpaqueValueInRenderPhaseInDEV(): boolean | void {
2036
}
2037
}
2038
2048
-function warnOnOpaqueIdentifierAccessInDEV(fiber) {
2049
- if (__DEV__) {
2050
- // TODO: Should warn in effects and callbacks, too
2051
- const name = getComponentNameFromFiber(fiber) || 'Unknown';
2052
- if (getIsRendering() && !didWarnAboutUseOpaqueIdentifier[name]) {
2053
- console.error(
2054
- 'The object passed back from useOpaqueIdentifier is meant to be ' +
2055
- 'passed through to attributes only. Do not read the ' +
2056
- 'value directly.',
2057
- );
2058
- didWarnAboutUseOpaqueIdentifier[name] = true;
2059
- }
2060
- }
2061
-}
2062
-
2063
-function mountOpaqueIdentifier(): OpaqueIDType | void {
2064
- const makeId = __DEV__
2065
- ? makeClientIdInDEV.bind(
2066
- null,
2067
- warnOnOpaqueIdentifierAccessInDEV.bind(null, currentlyRenderingFiber),
2068
- )
2069
- : makeClientId;
2070
-
2071
- if (getIsHydrating()) {
2072
- let didUpgrade = false;
2073
- const fiber = currentlyRenderingFiber;
2074
- const readValue = () => {
2075
- if (!didUpgrade) {
2076
- // Only upgrade once. This works even inside the render phase because
2077
- // the update is added to a shared queue, which outlasts the
2078
- // in-progress render.
2079
- didUpgrade = true;
2080
- if (__DEV__) {
2081
- isUpdatingOpaqueValueInRenderPhase = true;
2082
- setId(makeId());
2083
- isUpdatingOpaqueValueInRenderPhase = false;
2084
- warnOnOpaqueIdentifierAccessInDEV(fiber);
2085
- } else {
2086
- setId(makeId());
2087
- }
2088
- }
2089
-
2090
- throw new Error(
2091
- 'The object passed back from useOpaqueIdentifier is meant to be ' +
2092
- 'passed through to attributes only. Do not read the value directly.',
2093
- );
2094
- };
2095
- const id = makeOpaqueHydratingObject(readValue);
2096
-
2097
- const setId = mountState(id)[1];
2098
-
2099
- if ((currentlyRenderingFiber.mode & ConcurrentMode) === NoMode) {
2100
- if (
2101
- __DEV__ &&
2102
- enableStrictEffects &&
2103
- (currentlyRenderingFiber.mode & StrictEffectsMode) === NoMode
2104
- ) {
2105
- currentlyRenderingFiber.flags |= MountPassiveDevEffect | PassiveEffect;
2106
- } else {
2107
- currentlyRenderingFiber.flags |= PassiveEffect;
2108
- }
2109
- pushEffect(
2110
- HookHasEffect | HookPassive,
2111
- () => {
2112
- setId(makeId());
2113
- },
2114
- undefined,
2115
- null,
2116
- );
2117
- }
2118
- return id;
2119
- } else {
2120
- const id = makeId();
2121
- mountState(id);
2122
- return id;
2123
- }
2124
-}
2125
-
2126
-function updateOpaqueIdentifier(): OpaqueIDType | void {
2127
- const id = updateState(undefined)[0];
2128
- return id;
2129
-}
2130
-
2131
-function rerenderOpaqueIdentifier(): OpaqueIDType | void {
2132
- const id = rerenderState(undefined)[0];
2133
- return id;
2134
-}
2135
-
2039
function mountId(): string {
2040
const hook = mountWorkInProgressHook();
2041
@@ -2481,7 +2384,6 @@ export const ContextOnlyDispatcher: Dispatcher = {
2384
useTransition: throwInvalidHookError,
2385
useMutableSource: throwInvalidHookError,
2386
useSyncExternalStore: throwInvalidHookError,
2484
- useOpaqueIdentifier: throwInvalidHookError,
2387
useId: throwInvalidHookError,
2388
2389
unstable_isNewReconciler: enableNewReconciler,
@@ -2510,7 +2412,6 @@ const HooksDispatcherOnMount: Dispatcher = {
2412
useTransition: mountTransition,
2413
useMutableSource: mountMutableSource,
2414
useSyncExternalStore: mountSyncExternalStore,
2513
- useOpaqueIdentifier: mountOpaqueIdentifier,
2415
useId: mountId,
2416
2417
unstable_isNewReconciler: enableNewReconciler,
@@ -2539,7 +2440,6 @@ const HooksDispatcherOnUpdate: Dispatcher = {
2440
useTransition: updateTransition,
2441
useMutableSource: updateMutableSource,
2442
useSyncExternalStore: updateSyncExternalStore,
2542
- useOpaqueIdentifier: updateOpaqueIdentifier,
2443
useId: updateId,
2444
2445
unstable_isNewReconciler: enableNewReconciler,
@@ -2568,7 +2468,6 @@ const HooksDispatcherOnRerender: Dispatcher = {
2468
useTransition: rerenderTransition,
2469
useMutableSource: updateMutableSource,
2470
useSyncExternalStore: mountSyncExternalStore,
2571
- useOpaqueIdentifier: rerenderOpaqueIdentifier,
2471
useId: updateId,
2472
2473
unstable_isNewReconciler: enableNewReconciler,
@@ -2736,11 +2635,6 @@ if (__DEV__) {
2635
mountHookTypesDev();
2636
return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2637
},
2739
- useOpaqueIdentifier(): OpaqueIDType | void {
2740
- currentHookNameInDev = 'useOpaqueIdentifier';
2741
- mountHookTypesDev();
2742
- return mountOpaqueIdentifier();
2743
- },
2638
useId(): string {
2639
currentHookNameInDev = 'useId';
2640
mountHookTypesDev();
@@ -2883,11 +2777,6 @@ if (__DEV__) {
2777
updateHookTypesDev();
2778
return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2779
},
2886
- useOpaqueIdentifier(): OpaqueIDType | void {
2887
- currentHookNameInDev = 'useOpaqueIdentifier';
2888
- updateHookTypesDev();
2889
- return mountOpaqueIdentifier();
2890
- },
2780
useId(): string {
2781
currentHookNameInDev = 'useId';
2782
updateHookTypesDev();
@@ -3030,11 +2919,6 @@ if (__DEV__) {
2919
updateHookTypesDev();
2920
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2921
},
3033
- useOpaqueIdentifier(): OpaqueIDType | void {
3034
- currentHookNameInDev = 'useOpaqueIdentifier';
3035
- updateHookTypesDev();
3036
- return updateOpaqueIdentifier();
3037
- },
2922
useId(): string {
2923
currentHookNameInDev = 'useId';
2924
updateHookTypesDev();
@@ -3178,11 +3062,6 @@ if (__DEV__) {
3062
updateHookTypesDev();
3063
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
3064
},
3181
- useOpaqueIdentifier(): OpaqueIDType | void {
3182
- currentHookNameInDev = 'useOpaqueIdentifier';
3183
- updateHookTypesDev();
3184
- return rerenderOpaqueIdentifier();
3185
- },
3065
useId(): string {
3066
currentHookNameInDev = 'useId';
3067
updateHookTypesDev();
@@ -3341,12 +3220,6 @@ if (__DEV__) {
3220
mountHookTypesDev();
3221
return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
3222
},
3344
- useOpaqueIdentifier(): OpaqueIDType | void {
3345
- currentHookNameInDev = 'useOpaqueIdentifier';
3346
- warnInvalidHookAccess();
3347
- mountHookTypesDev();
3348
- return mountOpaqueIdentifier();
3349
- },
3223
useId(): string {
3224
currentHookNameInDev = 'useId';
3225
warnInvalidHookAccess();
@@ -3506,12 +3379,6 @@ if (__DEV__) {
3379
updateHookTypesDev();
3380
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
3381
},
3509
- useOpaqueIdentifier(): OpaqueIDType | void {
3510
- currentHookNameInDev = 'useOpaqueIdentifier';
3511
- warnInvalidHookAccess();
3512
- updateHookTypesDev();
3513
- return updateOpaqueIdentifier();
3514
- },
3382
useId(): string {
3383
currentHookNameInDev = 'useId';
3384
warnInvalidHookAccess();
@@ -3672,12 +3539,6 @@ if (__DEV__) {
3539
updateHookTypesDev();
3540
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
3541
},
3675
- useOpaqueIdentifier(): OpaqueIDType | void {
3676
- currentHookNameInDev = 'useOpaqueIdentifier';
3677
- warnInvalidHookAccess();
3678
- updateHookTypesDev();
3679
- return rerenderOpaqueIdentifier();
3680
- },
3542
useId(): string {
3543
currentHookNameInDev = 'useId';
3544
warnInvalidHookAccess();
packages/react-reconciler/src/ReactFiberHooks.old.js
-139
@@ -17,7 +17,6 @@ import type {Fiber, Dispatcher, HookType} from './ReactInternalTypes';
17
import type {Lanes, Lane} from './ReactFiberLane.old';
18
import type {HookFlags} from './ReactHookEffectTags';
19
import type {FiberRoot} from './ReactInternalTypes';
20
-import type {OpaqueIDType} from './ReactFiberHostConfig';
20
import type {Cache} from './ReactFiberCacheComponent.old';
21
import type {Flags} from './ReactFiberFlags';
22
@@ -95,18 +94,12 @@ import {
94
checkIfWorkInProgressReceivedUpdate,
95
} from './ReactFiberBeginWork.old';
96
import {getIsHydrating} from './ReactFiberHydrationContext.old';
98
-import {
99
- makeClientId,
100
- makeClientIdInDEV,
101
- makeOpaqueHydratingObject,
102
-} from './ReactFiberHostConfig';
97
import {
98
getWorkInProgressVersion,
99
markSourceAsDirty,
100
setWorkInProgressVersion,
101
warnAboutMultipleRenderersDEV,
102
} from './ReactMutableSource.old';
109
-import {getIsRendering} from './ReactCurrentFiber';
103
import {logStateUpdateScheduled} from './DebugTracing';
104
import {markStateUpdateScheduled} from './SchedulingProfiler';
105
import {createCache, CacheContext} from './ReactFiberCacheComponent.old';
@@ -139,10 +132,8 @@ export type UpdateQueue<S, A> = {|
132
|};
133
134
let didWarnAboutMismatchedHooksForComponent;
142
-let didWarnAboutUseOpaqueIdentifier;
135
let didWarnUncachedGetSnapshot;
136
if (__DEV__) {
145
- didWarnAboutUseOpaqueIdentifier = {};
137
didWarnAboutMismatchedHooksForComponent = new Set();
138
}
139
@@ -2045,94 +2036,6 @@ export function getIsUpdatingOpaqueValueInRenderPhaseInDEV(): boolean | void {
2036
}
2037
}
2038
2048
-function warnOnOpaqueIdentifierAccessInDEV(fiber) {
2049
- if (__DEV__) {
2050
- // TODO: Should warn in effects and callbacks, too
2051
- const name = getComponentNameFromFiber(fiber) || 'Unknown';
2052
- if (getIsRendering() && !didWarnAboutUseOpaqueIdentifier[name]) {
2053
- console.error(
2054
- 'The object passed back from useOpaqueIdentifier is meant to be ' +
2055
- 'passed through to attributes only. Do not read the ' +
2056
- 'value directly.',
2057
- );
2058
- didWarnAboutUseOpaqueIdentifier[name] = true;
2059
- }
2060
- }
2061
-}
2062
-
2063
-function mountOpaqueIdentifier(): OpaqueIDType | void {
2064
- const makeId = __DEV__
2065
- ? makeClientIdInDEV.bind(
2066
- null,
2067
- warnOnOpaqueIdentifierAccessInDEV.bind(null, currentlyRenderingFiber),
2068
- )
2069
- : makeClientId;
2070
-
2071
- if (getIsHydrating()) {
2072
- let didUpgrade = false;
2073
- const fiber = currentlyRenderingFiber;
2074
- const readValue = () => {
2075
- if (!didUpgrade) {
2076
- // Only upgrade once. This works even inside the render phase because
2077
- // the update is added to a shared queue, which outlasts the
2078
- // in-progress render.
2079
- didUpgrade = true;
2080
- if (__DEV__) {
2081
- isUpdatingOpaqueValueInRenderPhase = true;
2082
- setId(makeId());
2083
- isUpdatingOpaqueValueInRenderPhase = false;
2084
- warnOnOpaqueIdentifierAccessInDEV(fiber);
2085
- } else {
2086
- setId(makeId());
2087
- }
2088
- }
2089
-
2090
- throw new Error(
2091
- 'The object passed back from useOpaqueIdentifier is meant to be ' +
2092
- 'passed through to attributes only. Do not read the value directly.',
2093
- );
2094
- };
2095
- const id = makeOpaqueHydratingObject(readValue);
2096
-
2097
- const setId = mountState(id)[1];
2098
-
2099
- if ((currentlyRenderingFiber.mode & ConcurrentMode) === NoMode) {
2100
- if (
2101
- __DEV__ &&
2102
- enableStrictEffects &&
2103
- (currentlyRenderingFiber.mode & StrictEffectsMode) === NoMode
2104
- ) {
2105
- currentlyRenderingFiber.flags |= MountPassiveDevEffect | PassiveEffect;
2106
- } else {
2107
- currentlyRenderingFiber.flags |= PassiveEffect;
2108
- }
2109
- pushEffect(
2110
- HookHasEffect | HookPassive,
2111
- () => {
2112
- setId(makeId());
2113
- },
2114
- undefined,
2115
- null,
2116
- );
2117
- }
2118
- return id;
2119
- } else {
2120
- const id = makeId();
2121
- mountState(id);
2122
- return id;
2123
- }
2124
-}
2125
-
2126
-function updateOpaqueIdentifier(): OpaqueIDType | void {
2127
- const id = updateState(undefined)[0];
2128
- return id;
2129
-}
2130
-
2131
-function rerenderOpaqueIdentifier(): OpaqueIDType | void {
2132
- const id = rerenderState(undefined)[0];
2133
- return id;
2134
-}
2135
-
2039
function mountId(): string {
2040
const hook = mountWorkInProgressHook();
2041
@@ -2481,7 +2384,6 @@ export const ContextOnlyDispatcher: Dispatcher = {
2384
useTransition: throwInvalidHookError,
2385
useMutableSource: throwInvalidHookError,
2386
useSyncExternalStore: throwInvalidHookError,
2484
- useOpaqueIdentifier: throwInvalidHookError,
2387
useId: throwInvalidHookError,
2388
2389
unstable_isNewReconciler: enableNewReconciler,
@@ -2510,7 +2412,6 @@ const HooksDispatcherOnMount: Dispatcher = {
2412
useTransition: mountTransition,
2413
useMutableSource: mountMutableSource,
2414
useSyncExternalStore: mountSyncExternalStore,
2513
- useOpaqueIdentifier: mountOpaqueIdentifier,
2415
useId: mountId,
2416
2417
unstable_isNewReconciler: enableNewReconciler,
@@ -2539,7 +2440,6 @@ const HooksDispatcherOnUpdate: Dispatcher = {
2440
useTransition: updateTransition,
2441
useMutableSource: updateMutableSource,
2442
useSyncExternalStore: updateSyncExternalStore,
2542
- useOpaqueIdentifier: updateOpaqueIdentifier,
2443
useId: updateId,
2444
2445
unstable_isNewReconciler: enableNewReconciler,
@@ -2568,7 +2468,6 @@ const HooksDispatcherOnRerender: Dispatcher = {
2468
useTransition: rerenderTransition,
2469
useMutableSource: updateMutableSource,
2470
useSyncExternalStore: mountSyncExternalStore,
2571
- useOpaqueIdentifier: rerenderOpaqueIdentifier,
2471
useId: updateId,
2472
2473
unstable_isNewReconciler: enableNewReconciler,
@@ -2736,11 +2635,6 @@ if (__DEV__) {
2635
mountHookTypesDev();
2636
return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2637
},
2739
- useOpaqueIdentifier(): OpaqueIDType | void {
2740
- currentHookNameInDev = 'useOpaqueIdentifier';
2741
- mountHookTypesDev();
2742
- return mountOpaqueIdentifier();
2743
- },
2638
useId(): string {
2639
currentHookNameInDev = 'useId';
2640
mountHookTypesDev();
@@ -2883,11 +2777,6 @@ if (__DEV__) {
2777
updateHookTypesDev();
2778
return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2779
},
2886
- useOpaqueIdentifier(): OpaqueIDType | void {
2887
- currentHookNameInDev = 'useOpaqueIdentifier';
2888
- updateHookTypesDev();
2889
- return mountOpaqueIdentifier();
2890
- },
2780
useId(): string {
2781
currentHookNameInDev = 'useId';
2782
updateHookTypesDev();
@@ -3030,11 +2919,6 @@ if (__DEV__) {
2919
updateHookTypesDev();
2920
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2921
},
3033
- useOpaqueIdentifier(): OpaqueIDType | void {
3034
- currentHookNameInDev = 'useOpaqueIdentifier';
3035
- updateHookTypesDev();
3036
- return updateOpaqueIdentifier();
3037
- },
2922
useId(): string {
2923
currentHookNameInDev = 'useId';
2924
updateHookTypesDev();
@@ -3178,11 +3062,6 @@ if (__DEV__) {
3062
updateHookTypesDev();
3063
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
3064
},
3181
- useOpaqueIdentifier(): OpaqueIDType | void {
3182
- currentHookNameInDev = 'useOpaqueIdentifier';
3183
- updateHookTypesDev();
3184
- return rerenderOpaqueIdentifier();
3185
- },
3065
useId(): string {
3066
currentHookNameInDev = 'useId';
3067
updateHookTypesDev();
@@ -3341,12 +3220,6 @@ if (__DEV__) {
3220
mountHookTypesDev();
3221
return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
3222
},
3344
- useOpaqueIdentifier(): OpaqueIDType | void {
3345
- currentHookNameInDev = 'useOpaqueIdentifier';
3346
- warnInvalidHookAccess();
3347
- mountHookTypesDev();
3348
- return mountOpaqueIdentifier();
3349
- },
3223
useId(): string {
3224
currentHookNameInDev = 'useId';
3225
warnInvalidHookAccess();
@@ -3506,12 +3379,6 @@ if (__DEV__) {
3379
updateHookTypesDev();
3380
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
3381
},
3509
- useOpaqueIdentifier(): OpaqueIDType | void {
3510
- currentHookNameInDev = 'useOpaqueIdentifier';
3511
- warnInvalidHookAccess();
3512
- updateHookTypesDev();
3513
- return updateOpaqueIdentifier();
3514
- },
3382
useId(): string {
3383
currentHookNameInDev = 'useId';
3384
warnInvalidHookAccess();
@@ -3672,12 +3539,6 @@ if (__DEV__) {
3539
updateHookTypesDev();
3540
return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
3541
},
3675
- useOpaqueIdentifier(): OpaqueIDType | void {
3676
- currentHookNameInDev = 'useOpaqueIdentifier';
3677
- warnInvalidHookAccess();
3678
- updateHookTypesDev();
3679
- return rerenderOpaqueIdentifier();
3680
- },
3542
useId(): string {
3543
currentHookNameInDev = 'useId';
3544
warnInvalidHookAccess();
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+5
-8
@@ -474,8 +474,7 @@ export function scheduleUpdateOnFiber(
474
// if the update originates from user space (with the exception of local
475
// hook updates, which are handled differently and don't reach this
476
// function), but there are some internal React features that use this as
477
- // an implementation detail, like selective hydration
478
- // and useOpaqueIdentifier.
477
+ // an implementation detail, like selective hydration.
478
warnAboutRenderPhaseUpdatesInDEV(fiber);
479
480
// Track lanes that were updated during the render phase
@@ -898,12 +897,10 @@ function recoverFromConcurrentError(root, errorRetryLanes) {
897
exitStatus === RootErrored &&
898
workInProgressRootRenderPhaseUpdatedLanes !== NoLanes
899
) {
901
- // There was a render phase update during this render. This was likely a
902
- // useOpaqueIdentifier hook upgrading itself to a client ID. Try rendering
903
- // again. This time, the component will use a client ID and will proceed
904
- // without throwing. If multiple IDs upgrade as a result of the same
905
- // update, we will have to do multiple render passes. To protect against
906
- // an inifinite loop, eventually we'll give up.
900
+ // There was a render phase update during this render. Some internal React
901
+ // implementation details may use this as a trick to schedule another
902
+ // render pass. To protect against an inifinite loop, eventually
903
+ // we'll give up.
904
continue;
905
}
906
break;
packages/react-reconciler/src/ReactFiberWorkLoop.old.js
+5
-8
@@ -474,8 +474,7 @@ export function scheduleUpdateOnFiber(
474
// if the update originates from user space (with the exception of local
475
// hook updates, which are handled differently and don't reach this
476
// function), but there are some internal React features that use this as
477
- // an implementation detail, like selective hydration
478
- // and useOpaqueIdentifier.
477
+ // an implementation detail, like selective hydration.
478
warnAboutRenderPhaseUpdatesInDEV(fiber);
479
480
// Track lanes that were updated during the render phase
@@ -898,12 +897,10 @@ function recoverFromConcurrentError(root, errorRetryLanes) {
897
exitStatus === RootErrored &&
898
workInProgressRootRenderPhaseUpdatedLanes !== NoLanes
899
) {
901
- // There was a render phase update during this render. This was likely a
902
- // useOpaqueIdentifier hook upgrading itself to a client ID. Try rendering
903
- // again. This time, the component will use a client ID and will proceed
904
- // without throwing. If multiple IDs upgrade as a result of the same
905
- // update, we will have to do multiple render passes. To protect against
906
- // an inifinite loop, eventually we'll give up.
900
+ // There was a render phase update during this render. Some internal React
901
+ // implementation details may use this as a trick to schedule another
902
+ // render pass. To protect against an inifinite loop, eventually
903
+ // we'll give up.
904
continue;
905
}
906
break;
packages/react-reconciler/src/ReactInternalTypes.js
-2
@@ -43,7 +43,6 @@ export type HookType =
43
| 'useTransition'
44
| 'useMutableSource'
45
| 'useSyncExternalStore'
46
- | 'useOpaqueIdentifier'
46
| 'useId'
47
| 'useCacheRefresh';
48
@@ -317,7 +316,6 @@ export type Dispatcher = {|
316
getSnapshot: () => T,
317
getServerSnapshot?: () => T,
318
): T,
320
- useOpaqueIdentifier(): any,
319
useId(): string,
320
useCacheRefresh?: () => <T>(?() => T, ?T) => void,
321
packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js
+8
-8
@@ -1916,14 +1916,14 @@ describe('ReactIncrementalErrorHandling', () => {
1916
});
1917
1918
it("does not infinite loop if there's a render phase update in the same render as an error", async () => {
1919
- // useOpaqueIdentifier uses an render phase update as an implementation
1920
- // detail. When an error is accompanied by a render phase update, we assume
1921
- // that it comes from useOpaqueIdentifier, because render phase updates
1922
- // triggered from userspace are not allowed (we log a warning). So we keep
1923
- // attempting to recover until no more opaque identifiers need to be
1924
- // upgraded. However, we should give up after some point to prevent an
1925
- // infinite loop in the case where there is (by accident) a render phase
1926
- // triggered from userspace.
1919
+ // Some React features may schedule a render phase update as an
1920
+ // implementation detail. When an error is accompanied by a render phase
1921
+ // update, we assume that it comes from React internals, because render
1922
+ // phase updates triggered from userspace are not allowed (we log a
1923
+ // warning). So we keep attempting to recover until no more opaque
1924
+ // identifiers need to be upgraded. However, we should give up after some
1925
+ // point to prevent an infinite loop in the case where there is (by
1926
+ // accident) a render phase triggered from userspace.
1927
1928
spyOnDev(console, 'error');
1929
packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js
-6
@@ -38,7 +38,6 @@ export opaque type ChildSet = mixed; // eslint-disable-line no-undef
38
export opaque type TimeoutHandle = mixed; // eslint-disable-line no-undef
39
export opaque type NoTimeout = mixed; // eslint-disable-line no-undef
40
export opaque type RendererInspectionConfig = mixed; // eslint-disable-line no-undef
41
-export opaque type OpaqueIDType = mixed;
41
export type EventResponder = any;
42
43
export const getPublicInstance = $$$hostConfig.getPublicInstance;
@@ -62,11 +61,6 @@ export const supportsMutation = $$$hostConfig.supportsMutation;
61
export const supportsPersistence = $$$hostConfig.supportsPersistence;
62
export const supportsHydration = $$$hostConfig.supportsHydration;
63
export const getInstanceFromNode = $$$hostConfig.getInstanceFromNode;
65
-export const isOpaqueHydratingObject = $$$hostConfig.isOpaqueHydratingObject;
66
-export const makeOpaqueHydratingObject =
67
- $$$hostConfig.makeOpaqueHydratingObject;
68
-export const makeClientId = $$$hostConfig.makeClientId;
69
-export const makeClientIdInDEV = $$$hostConfig.makeClientIdInDEV;
64
export const beforeActiveInstanceBlur = $$$hostConfig.beforeActiveInstanceBlur;
65
export const afterActiveInstanceBlur = $$$hostConfig.afterActiveInstanceBlur;
66
export const preparePortalMount = $$$hostConfig.preparePortalMount;
packages/react-server/src/ReactFizzHooks.js
+1
-8
@@ -16,14 +16,12 @@ import type {
16
ReactContext,
17
} from 'shared/ReactTypes';
18
19
-import type {ResponseState, OpaqueIDType} from './ReactServerFormatConfig';
19
+import type {ResponseState} from './ReactServerFormatConfig';
20
import type {Task} from './ReactFizzServer';
21
22
import {readContext as readContextImpl} from './ReactFizzNewContext';
23
import {getTreeId} from './ReactFizzTreeContext';
24
25
-import {makeServerID} from './ReactServerFormatConfig';
26
-
25
import {enableCache} from 'shared/ReactFeatureFlags';
26
import is from 'shared/objectIs';
27
@@ -509,10 +507,6 @@ function useTransition(): [boolean, (callback: () => void) => void] {
507
return [false, unsupportedStartTransition];
508
}
509
512
-function useOpaqueIdentifier(): OpaqueIDType {
513
- return makeServerID(currentResponseState);
514
-}
515
-
510
function useId(): string {
511
const task: Task = (currentlyRenderingTask: any);
512
const treeId = getTreeId(task.treeContext);
@@ -559,7 +553,6 @@ export const Dispatcher: DispatcherType = {
553
useDebugValue: noop,
554
useDeferredValue,
555
useTransition,
562
- useOpaqueIdentifier,
556
useId,
557
// Subscriptions are not setup in a server environment.
558
useMutableSource,
packages/react-server/src/ReactFlightServer.js
-1
@@ -845,7 +845,6 @@ const Dispatcher: DispatcherType = {
845
useLayoutEffect: (unsupportedHook: any),
846
useImperativeHandle: (unsupportedHook: any),
847
useEffect: (unsupportedHook: any),
848
- useOpaqueIdentifier: (unsupportedHook: any),
848
useId: (unsupportedHook: any),
849
useMutableSource: (unsupportedHook: any),
850
useSyncExternalStore: (unsupportedHook: any),
packages/react-server/src/forks/ReactServerFormatConfig.custom.js
-2
@@ -28,7 +28,6 @@ export opaque type Destination = mixed; // eslint-disable-line no-undef
28
export opaque type ResponseState = mixed;
29
export opaque type FormatContext = mixed;
30
export opaque type SuspenseBoundaryID = mixed;
31
-export opaque type OpaqueIDType = mixed;
31
32
export const isPrimaryRenderer = false;
33
@@ -36,7 +35,6 @@ export const getChildFormatContext = $$$hostConfig.getChildFormatContext;
35
export const UNINITIALIZED_SUSPENSE_BOUNDARY_ID =
36
$$$hostConfig.UNINITIALIZED_SUSPENSE_BOUNDARY_ID;
37
export const assignSuspenseBoundaryID = $$$hostConfig.assignSuspenseBoundaryID;
39
-export const makeServerID = $$$hostConfig.makeServerID;
38
export const pushTextInstance = $$$hostConfig.pushTextInstance;
39
export const pushStartInstance = $$$hostConfig.pushStartInstance;
40
export const pushEndInstance = $$$hostConfig.pushEndInstance;
packages/react-suspense-test-utils/src/ReactSuspenseTestUtils.js
-1
@@ -42,7 +42,6 @@ export function waitForSuspense<T>(fn: () => T): Promise<T> {
42
useDebugValue: unsupported,
43
useDeferredValue: unsupported,
44
useTransition: unsupported,
45
- useOpaqueIdentifier: unsupported,
45
useId: unsupported,
46
useMutableSource: unsupported,
47
useSyncExternalStore: unsupported,
packages/react-test-renderer/src/ReactTestHostConfig.js
-44
@@ -7,7 +7,6 @@
7
* @flow
8
*/
9
10
-import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
10
import isArray from 'shared/isArray';
11
import {DefaultEventPriority} from 'react-reconciler/src/ReactEventPriorities';
12
@@ -40,12 +39,6 @@ export type ChildSet = void; // Unused
39
export type TimeoutHandle = TimeoutID;
40
export type NoTimeout = -1;
41
export type EventResponder = any;
43
-export opaque type OpaqueIDType =
44
- | string
45
- | {
46
- toString: () => string | void,
47
- valueOf: () => string | void,
48
- };
42
43
export type RendererInspectionConfig = $ReadOnly<{||}>;
44
@@ -298,43 +291,6 @@ export function getInstanceFromNode(mockNode: Object) {
291
return null;
292
}
293
301
-let clientId: number = 0;
302
-export function makeClientId(): OpaqueIDType {
303
- return 'c_' + (clientId++).toString(36);
304
-}
305
-
306
-export function makeClientIdInDEV(warnOnAccessInDEV: () => void): OpaqueIDType {
307
- const id = 'c_' + (clientId++).toString(36);
308
- return {
309
- toString() {
310
- warnOnAccessInDEV();
311
- return id;
312
- },
313
- valueOf() {
314
- warnOnAccessInDEV();
315
- return id;
316
- },
317
- };
318
-}
319
-
320
-export function isOpaqueHydratingObject(value: mixed): boolean {
321
- return (
322
- value !== null &&
323
- typeof value === 'object' &&
324
- value.$$typeof === REACT_OPAQUE_ID_TYPE
325
- );
326
-}
327
-
328
-export function makeOpaqueHydratingObject(
329
- attemptToReadValue: () => void,
330
-): OpaqueIDType {
331
- return {
332
- $$typeof: REACT_OPAQUE_ID_TYPE,
333
- toString: attemptToReadValue,
334
- valueOf: attemptToReadValue,
335
- };
336
-}
337
-
294
export function beforeActiveInstanceBlur(internalInstanceHandle: Object) {
295
// noop
296
}
packages/react/index.classic.fb.js
-1
@@ -40,7 +40,6 @@ export {
40
unstable_getCacheSignal,
41
unstable_getCacheForType,
42
unstable_useCacheRefresh,
43
- unstable_useOpaqueIdentifier,
43
unstable_useId,
44
useCallback,
45
useContext,
packages/react/index.experimental.js
-1
@@ -36,7 +36,6 @@ export {
36
unstable_getCacheSignal,
37
unstable_getCacheForType,
38
unstable_useCacheRefresh,
39
- unstable_useOpaqueIdentifier,
39
unstable_useId,
40
useCallback,
41
useContext,
packages/react/index.js
-1
@@ -61,7 +61,6 @@ export {
61
unstable_getCacheSignal,
62
unstable_getCacheForType,
63
unstable_useCacheRefresh,
64
- unstable_useOpaqueIdentifier,
64
unstable_useId,
65
useCallback,
66
useContext,
packages/react/index.modern.fb.js
-1
@@ -39,7 +39,6 @@ export {
39
unstable_getCacheSignal,
40
unstable_getCacheForType,
41
unstable_useCacheRefresh,
42
- unstable_useOpaqueIdentifier,
42
unstable_useId,
43
useCallback,
44
useContext,
packages/react/index.stable.js
-1
@@ -29,7 +29,6 @@ export {
29
lazy,
30
memo,
31
startTransition,
32
- unstable_useOpaqueIdentifier,
32
unstable_useId,
33
useCallback,
34
useContext,
packages/react/src/React.js
-2
@@ -52,7 +52,6 @@ import {
52
useState,
53
useTransition,
54
useDeferredValue,
55
- useOpaqueIdentifier,
55
useId,
56
useCacheRefresh,
57
} from './ReactHooks';
@@ -127,7 +126,6 @@ export {
126
REACT_CACHE_TYPE as unstable_Cache,
127
// enableScopeAPI
128
REACT_SCOPE_TYPE as unstable_Scope,
130
- useOpaqueIdentifier as unstable_useOpaqueIdentifier,
129
useId as unstable_useId,
130
act,
131
};
packages/react/src/ReactHooks.js
-6
@@ -14,7 +14,6 @@ import type {
14
MutableSourceSubscribeFn,
15
ReactContext,
16
} from 'shared/ReactTypes';
17
-import type {OpaqueIDType} from 'react-reconciler/src/ReactFiberHostConfig';
17
18
import ReactCurrentDispatcher from './ReactCurrentDispatcher';
19
@@ -169,11 +168,6 @@ export function useDeferredValue<T>(value: T): T {
168
return dispatcher.useDeferredValue(value);
169
}
170
172
-export function useOpaqueIdentifier(): OpaqueIDType | void {
173
- const dispatcher = resolveDispatcher();
174
- return dispatcher.useOpaqueIdentifier();
175
-}
176
-
171
export function useId(): string {
172
const dispatcher = resolveDispatcher();
173
return dispatcher.useId();
packages/react/unstable-shared-subset.experimental.js
-1
@@ -27,7 +27,6 @@ export {
27
unstable_DebugTracingMode,
28
unstable_getCacheSignal,
29
unstable_getCacheForType,
30
- unstable_useOpaqueIdentifier,
30
unstable_useId,
31
useCallback,
32
useContext,
packages/shared/CheckStringCoercion.js
-12
@@ -7,8 +7,6 @@
7
* @flow
8
*/
9
10
-import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
11
-
10
/*
11
* The `'' + value` pattern (used in in perf-sensitive code) throws for Symbol
12
* and Temporal.* types. See https://github.com/facebook/react/pull/22064.
@@ -35,16 +33,6 @@ function typeName(value: mixed): string {
33
// $FlowFixMe only called in DEV, so void return is not possible.
34
function willCoercionThrow(value: mixed): boolean {
35
if (__DEV__) {
38
- if (
39
- value !== null &&
40
- typeof value === 'object' &&
41
- value.$$typeof === REACT_OPAQUE_ID_TYPE
42
- ) {
43
- // OpaqueID type is expected to throw, so React will handle it. Not sure if
44
- // it's expected that string coercion will throw, but we'll assume it's OK.
45
- // See https://github.com/facebook/react/issues/20127.
46
- return;
47
- }
36
try {
37
testStringCoercion(value);
38
return false;
packages/shared/ReactSymbols.js
-2
@@ -26,7 +26,6 @@ export let REACT_SUSPENSE_LIST_TYPE = 0xead8;
26
export let REACT_MEMO_TYPE = 0xead3;
27
export let REACT_LAZY_TYPE = 0xead4;
28
export let REACT_SCOPE_TYPE = 0xead7;
29
-export let REACT_OPAQUE_ID_TYPE = 0xeae0;
29
export let REACT_DEBUG_TRACING_MODE_TYPE = 0xeae1;
30
export let REACT_OFFSCREEN_TYPE = 0xeae2;
31
export let REACT_LEGACY_HIDDEN_TYPE = 0xeae3;
@@ -47,7 +46,6 @@ if (typeof Symbol === 'function' && Symbol.for) {
46
REACT_MEMO_TYPE = symbolFor('react.memo');
47
REACT_LAZY_TYPE = symbolFor('react.lazy');
48
REACT_SCOPE_TYPE = symbolFor('react.scope');
50
- REACT_OPAQUE_ID_TYPE = symbolFor('react.opaque.id');
49
REACT_DEBUG_TRACING_MODE_TYPE = symbolFor('react.debug_trace_mode');
50
REACT_OFFSCREEN_TYPE = symbolFor('react.offscreen');
51
REACT_LEGACY_HIDDEN_TYPE = symbolFor('react.legacy_hidden');
scripts/error-codes/codes.json
+1
-1
@@ -342,7 +342,7 @@
342
"352": "React Lazy Components are not yet supported on the server.",
343
"353": "A server block should never encode any other slots. This is a bug in React.",
344
"354": "getInspectorDataForViewAtPoint() is not available in production.",
345
- "355": "The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. Do not read the value directly.",
345
+ "355": "The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. Do not read the value directly. (TODO: This feature was never released so we should be able to remove this error from the map.)",
346
"356": "Could not read the cache.",
347
"357": "The current renderer does not support React Scopes. This error is likely caused by a bug in React. Please file an issue.",
348
"358": "Invalid update priority: %s. This is a bug in React.",