Refactor React Server entrypoint to not depend on the client one (#27940)
This refactors the Server Components entrypoint for the `react` package (ReactServer.js) so that it doesn't depend on the client entrypoint (React.js). I also renamed React.js to ReactClient.js to make the separation clearer. This structure will make it easier to add client-only and server-only features.
Andrew Clark committed
Jan 16, 2024 at 20:19 UTC
f16344ea6db5bcc108de80dbc39a41ec28e8210d
11 files changed
+695
-608
packages/react/index.classic.fb.js
+1
-1
@@ -58,5 +58,5 @@ export {
58
useSyncExternalStore,
59
useTransition,
60
version,
61
-} from './src/React';
61
+} from './src/ReactClient';
62
export {jsx, jsxs, jsxDEV} from './src/jsx/ReactJSX';
packages/react/index.experimental.js
+2
-2
@@ -57,9 +57,9 @@ export {
57
useSyncExternalStore,
58
useTransition,
59
version,
60
-} from './src/React';
60
+} from './src/ReactClient';
61
62
-import {useOptimistic} from './src/React';
62
+import {useOptimistic} from './src/ReactClient';
63
64
export function experimental_useOptimistic<S, A>(
65
passthrough: S,
packages/react/index.js
+1
-1
@@ -80,4 +80,4 @@ export {
80
useState,
81
useTransition,
82
version,
83
-} from './src/React';
83
+} from './src/ReactClient';
packages/react/index.modern.fb.js
+1
-1
@@ -56,5 +56,5 @@ export {
56
useSyncExternalStore,
57
useTransition,
58
version,
59
-} from './src/React';
59
+} from './src/ReactClient';
60
export {jsx, jsxs, jsxDEV} from './src/jsx/ReactJSX';
packages/react/index.stable.js
+1
-1
@@ -47,4 +47,4 @@ export {
47
useSyncExternalStore,
48
useTransition,
49
version,
50
-} from './src/React';
50
+} from './src/ReactClient';
packages/react/src/ReactClient.js
renamed
+4
-19
@@ -26,9 +26,9 @@ import {Component, PureComponent} from './ReactBaseClasses';
26
import {createRef} from './ReactCreateRef';
27
import {forEach, map, count, toArray, only} from './ReactChildren';
28
import {
29
- createElement as createElementProd,
30
- createFactory as createFactoryProd,
31
- cloneElement as cloneElementProd,
29
+ createElement,
30
+ createFactory,
31
+ cloneElement,
32
isValidElement,
33
} from './ReactElement';
34
import {createContext} from './ReactContext';
@@ -61,27 +61,12 @@ import {
61
useMemoCache,
62
useOptimistic,
63
} from './ReactHooks';
64
-import {
65
- createElementWithValidation,
66
- createFactoryWithValidation,
67
- cloneElementWithValidation,
68
-} from './ReactElementValidator';
64
+
65
import {createServerContext} from './ReactServerContext';
66
import ReactSharedInternals from './ReactSharedInternalsClient';
67
import {startTransition} from './ReactStartTransition';
68
import {act} from './ReactAct';
69
74
-// TODO: Move this branching into the other module instead and just re-export.
75
-const createElement: any = __DEV__
76
- ? createElementWithValidation
77
- : createElementProd;
78
-const cloneElement: any = __DEV__
79
- ? cloneElementWithValidation
80
- : cloneElementProd;
81
-const createFactory: any = __DEV__
82
- ? createFactoryWithValidation
83
- : createFactoryProd;
84
-
70
const Children = {
71
map,
72
forEach,
packages/react/src/ReactElement.js
+26
-567
@@ -3,571 +3,30 @@
3
*
4
* This source code is licensed under the MIT license found in the
5
* LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-import getComponentNameFromType from 'shared/getComponentNameFromType';
9
-import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
10
-import assign from 'shared/assign';
11
-import hasOwnProperty from 'shared/hasOwnProperty';
12
-import {checkKeyStringCoercion} from 'shared/CheckStringCoercion';
13
-
14
-import ReactCurrentOwner from './ReactCurrentOwner';
15
-
16
-const RESERVED_PROPS = {
17
- key: true,
18
- ref: true,
19
- __self: true,
20
- __source: true,
21
-};
22
-
23
-let specialPropKeyWarningShown,
24
- specialPropRefWarningShown,
25
- didWarnAboutStringRefs;
26
-
27
-if (__DEV__) {
28
- didWarnAboutStringRefs = {};
29
-}
30
-
31
-function hasValidRef(config) {
32
- if (__DEV__) {
33
- if (hasOwnProperty.call(config, 'ref')) {
34
- const getter = Object.getOwnPropertyDescriptor(config, 'ref').get;
35
- if (getter && getter.isReactWarning) {
36
- return false;
37
- }
38
- }
39
- }
40
- return config.ref !== undefined;
41
-}
42
-
43
-function hasValidKey(config) {
44
- if (__DEV__) {
45
- if (hasOwnProperty.call(config, 'key')) {
46
- const getter = Object.getOwnPropertyDescriptor(config, 'key').get;
47
- if (getter && getter.isReactWarning) {
48
- return false;
49
- }
50
- }
51
- }
52
- return config.key !== undefined;
53
-}
54
-
55
-function defineKeyPropWarningGetter(props, displayName) {
56
- const warnAboutAccessingKey = function () {
57
- if (__DEV__) {
58
- if (!specialPropKeyWarningShown) {
59
- specialPropKeyWarningShown = true;
60
- console.error(
61
- '%s: `key` is not a prop. Trying to access it will result ' +
62
- 'in `undefined` being returned. If you need to access the same ' +
63
- 'value within the child component, you should pass it as a different ' +
64
- 'prop. (https://reactjs.org/link/special-props)',
65
- displayName,
66
- );
67
- }
68
- }
69
- };
70
- warnAboutAccessingKey.isReactWarning = true;
71
- Object.defineProperty(props, 'key', {
72
- get: warnAboutAccessingKey,
73
- configurable: true,
74
- });
75
-}
76
-
77
-function defineRefPropWarningGetter(props, displayName) {
78
- const warnAboutAccessingRef = function () {
79
- if (__DEV__) {
80
- if (!specialPropRefWarningShown) {
81
- specialPropRefWarningShown = true;
82
- console.error(
83
- '%s: `ref` is not a prop. Trying to access it will result ' +
84
- 'in `undefined` being returned. If you need to access the same ' +
85
- 'value within the child component, you should pass it as a different ' +
86
- 'prop. (https://reactjs.org/link/special-props)',
87
- displayName,
88
- );
89
- }
90
- }
91
- };
92
- warnAboutAccessingRef.isReactWarning = true;
93
- Object.defineProperty(props, 'ref', {
94
- get: warnAboutAccessingRef,
95
- configurable: true,
96
- });
97
-}
98
-
99
-function warnIfStringRefCannotBeAutoConverted(config) {
100
- if (__DEV__) {
101
- if (
102
- typeof config.ref === 'string' &&
103
- ReactCurrentOwner.current &&
104
- config.__self &&
105
- ReactCurrentOwner.current.stateNode !== config.__self
106
- ) {
107
- const componentName = getComponentNameFromType(
108
- ReactCurrentOwner.current.type,
109
- );
110
-
111
- if (!didWarnAboutStringRefs[componentName]) {
112
- console.error(
113
- 'Component "%s" contains the string ref "%s". ' +
114
- 'Support for string refs will be removed in a future major release. ' +
115
- 'This case cannot be automatically converted to an arrow function. ' +
116
- 'We ask you to manually fix this case by using useRef() or createRef() instead. ' +
117
- 'Learn more about using refs safely here: ' +
118
- 'https://reactjs.org/link/strict-mode-string-ref',
119
- componentName,
120
- config.ref,
121
- );
122
- didWarnAboutStringRefs[componentName] = true;
123
- }
124
- }
125
- }
126
-}
127
-
128
-/**
129
- * Factory method to create a new React element. This no longer adheres to
130
- * the class pattern, so do not use new to call it. Also, instanceof check
131
- * will not work. Instead test $$typeof field against Symbol.for('react.element') to check
132
- * if something is a React Element.
6
*
134
- * @param {*} type
135
- * @param {*} props
136
- * @param {*} key
137
- * @param {string|object} ref
138
- * @param {*} owner
139
- * @param {*} self A *temporary* helper to detect places where `this` is
140
- * different from the `owner` when React.createElement is called, so that we
141
- * can warn. We want to get rid of owner and replace string `ref`s with arrow
142
- * functions, and as long as `this` and owner are the same, there will be no
143
- * change in behavior.
144
- * @param {*} source An annotation object (added by a transpiler or otherwise)
145
- * indicating filename, line number, and/or other information.
146
- * @internal
147
- */
148
-function ReactElement(type, key, ref, self, source, owner, props) {
149
- const element = {
150
- // This tag allows us to uniquely identify this as a React Element
151
- $$typeof: REACT_ELEMENT_TYPE,
152
-
153
- // Built-in properties that belong on the element
154
- type: type,
155
- key: key,
156
- ref: ref,
157
- props: props,
158
-
159
- // Record the component responsible for creating this element.
160
- _owner: owner,
161
- };
162
-
163
- if (__DEV__) {
164
- // The validation flag is currently mutative. We put it on
165
- // an external backing store so that we can freeze the whole object.
166
- // This can be replaced with a WeakMap once they are implemented in
167
- // commonly used development environments.
168
- element._store = {};
169
-
170
- // To make comparing ReactElements easier for testing purposes, we make
171
- // the validation flag non-enumerable (where possible, which should
172
- // include every environment we run tests in), so the test framework
173
- // ignores it.
174
- Object.defineProperty(element._store, 'validated', {
175
- configurable: false,
176
- enumerable: false,
177
- writable: true,
178
- value: false,
179
- });
180
- // self and source are DEV only properties.
181
- Object.defineProperty(element, '_self', {
182
- configurable: false,
183
- enumerable: false,
184
- writable: false,
185
- value: self,
186
- });
187
- // Two elements created in two different places should be considered
188
- // equal for testing purposes and therefore we hide it from enumeration.
189
- Object.defineProperty(element, '_source', {
190
- configurable: false,
191
- enumerable: false,
192
- writable: false,
193
- value: source,
194
- });
195
- if (Object.freeze) {
196
- Object.freeze(element.props);
197
- Object.freeze(element);
198
- }
199
- }
200
-
201
- return element;
202
-}
203
-
204
-/**
205
- * https://github.com/reactjs/rfcs/pull/107
206
- * @param {*} type
207
- * @param {object} props
208
- * @param {string} key
209
- */
210
-export function jsx(type, config, maybeKey) {
211
- let propName;
212
-
213
- // Reserved names are extracted
214
- const props = {};
215
-
216
- let key = null;
217
- let ref = null;
218
-
219
- // Currently, key can be spread in as a prop. This causes a potential
220
- // issue if key is also explicitly declared (ie. <div {...props} key="Hi" />
221
- // or <div key="Hi" {...props} /> ). We want to deprecate key spread,
222
- // but as an intermediary step, we will use jsxDEV for everything except
223
- // <div {...props} key="Hi" />, because we aren't currently able to tell if
224
- // key is explicitly declared to be undefined or not.
225
- if (maybeKey !== undefined) {
226
- if (__DEV__) {
227
- checkKeyStringCoercion(maybeKey);
228
- }
229
- key = '' + maybeKey;
230
- }
231
-
232
- if (hasValidKey(config)) {
233
- if (__DEV__) {
234
- checkKeyStringCoercion(config.key);
235
- }
236
- key = '' + config.key;
237
- }
238
-
239
- if (hasValidRef(config)) {
240
- ref = config.ref;
241
- }
242
-
243
- // Remaining properties are added to a new props object
244
- for (propName in config) {
245
- if (
246
- hasOwnProperty.call(config, propName) &&
247
- !RESERVED_PROPS.hasOwnProperty(propName)
248
- ) {
249
- props[propName] = config[propName];
250
- }
251
- }
252
-
253
- // Resolve default props
254
- if (type && type.defaultProps) {
255
- const defaultProps = type.defaultProps;
256
- for (propName in defaultProps) {
257
- if (props[propName] === undefined) {
258
- props[propName] = defaultProps[propName];
259
- }
260
- }
261
- }
262
-
263
- return ReactElement(
264
- type,
265
- key,
266
- ref,
267
- undefined,
268
- undefined,
269
- ReactCurrentOwner.current,
270
- props,
271
- );
272
-}
273
-
274
-/**
275
- * https://github.com/reactjs/rfcs/pull/107
276
- * @param {*} type
277
- * @param {object} props
278
- * @param {string} key
279
- */
280
-export function jsxDEV(type, config, maybeKey, source, self) {
281
- let propName;
282
-
283
- // Reserved names are extracted
284
- const props = {};
285
-
286
- let key = null;
287
- let ref = null;
288
-
289
- // Currently, key can be spread in as a prop. This causes a potential
290
- // issue if key is also explicitly declared (ie. <div {...props} key="Hi" />
291
- // or <div key="Hi" {...props} /> ). We want to deprecate key spread,
292
- // but as an intermediary step, we will use jsxDEV for everything except
293
- // <div {...props} key="Hi" />, because we aren't currently able to tell if
294
- // key is explicitly declared to be undefined or not.
295
- if (maybeKey !== undefined) {
296
- if (__DEV__) {
297
- checkKeyStringCoercion(maybeKey);
298
- }
299
- key = '' + maybeKey;
300
- }
301
-
302
- if (hasValidKey(config)) {
303
- if (__DEV__) {
304
- checkKeyStringCoercion(config.key);
305
- }
306
- key = '' + config.key;
307
- }
308
-
309
- if (hasValidRef(config)) {
310
- ref = config.ref;
311
- warnIfStringRefCannotBeAutoConverted(config);
312
- }
313
-
314
- // Remaining properties are added to a new props object
315
- for (propName in config) {
316
- if (
317
- hasOwnProperty.call(config, propName) &&
318
- !RESERVED_PROPS.hasOwnProperty(propName)
319
- ) {
320
- props[propName] = config[propName];
321
- }
322
- }
323
-
324
- // Resolve default props
325
- if (type && type.defaultProps) {
326
- const defaultProps = type.defaultProps;
327
- for (propName in defaultProps) {
328
- if (props[propName] === undefined) {
329
- props[propName] = defaultProps[propName];
330
- }
331
- }
332
- }
333
-
334
- if (key || ref) {
335
- const displayName =
336
- typeof type === 'function'
337
- ? type.displayName || type.name || 'Unknown'
338
- : type;
339
- if (key) {
340
- defineKeyPropWarningGetter(props, displayName);
341
- }
342
- if (ref) {
343
- defineRefPropWarningGetter(props, displayName);
344
- }
345
- }
346
-
347
- return ReactElement(
348
- type,
349
- key,
350
- ref,
351
- self,
352
- source,
353
- ReactCurrentOwner.current,
354
- props,
355
- );
356
-}
357
-
358
-/**
359
- * Create and return a new ReactElement of the given type.
360
- * See https://reactjs.org/docs/react-api.html#createelement
361
- */
362
-export function createElement(type, config, children) {
363
- let propName;
364
-
365
- // Reserved names are extracted
366
- const props = {};
367
-
368
- let key = null;
369
- let ref = null;
370
- let self = null;
371
- let source = null;
372
-
373
- if (config != null) {
374
- if (hasValidRef(config)) {
375
- ref = config.ref;
376
-
377
- if (__DEV__) {
378
- warnIfStringRefCannotBeAutoConverted(config);
379
- }
380
- }
381
- if (hasValidKey(config)) {
382
- if (__DEV__) {
383
- checkKeyStringCoercion(config.key);
384
- }
385
- key = '' + config.key;
386
- }
387
-
388
- self = config.__self === undefined ? null : config.__self;
389
- source = config.__source === undefined ? null : config.__source;
390
- // Remaining properties are added to a new props object
391
- for (propName in config) {
392
- if (
393
- hasOwnProperty.call(config, propName) &&
394
- !RESERVED_PROPS.hasOwnProperty(propName)
395
- ) {
396
- props[propName] = config[propName];
397
- }
398
- }
399
- }
400
-
401
- // Children can be more than one argument, and those are transferred onto
402
- // the newly allocated props object.
403
- const childrenLength = arguments.length - 2;
404
- if (childrenLength === 1) {
405
- props.children = children;
406
- } else if (childrenLength > 1) {
407
- const childArray = Array(childrenLength);
408
- for (let i = 0; i < childrenLength; i++) {
409
- childArray[i] = arguments[i + 2];
410
- }
411
- if (__DEV__) {
412
- if (Object.freeze) {
413
- Object.freeze(childArray);
414
- }
415
- }
416
- props.children = childArray;
417
- }
418
-
419
- // Resolve default props
420
- if (type && type.defaultProps) {
421
- const defaultProps = type.defaultProps;
422
- for (propName in defaultProps) {
423
- if (props[propName] === undefined) {
424
- props[propName] = defaultProps[propName];
425
- }
426
- }
427
- }
428
- if (__DEV__) {
429
- if (key || ref) {
430
- const displayName =
431
- typeof type === 'function'
432
- ? type.displayName || type.name || 'Unknown'
433
- : type;
434
- if (key) {
435
- defineKeyPropWarningGetter(props, displayName);
436
- }
437
- if (ref) {
438
- defineRefPropWarningGetter(props, displayName);
439
- }
440
- }
441
- }
442
- return ReactElement(
443
- type,
444
- key,
445
- ref,
446
- self,
447
- source,
448
- ReactCurrentOwner.current,
449
- props,
450
- );
451
-}
452
-
453
-/**
454
- * Return a function that produces ReactElements of a given type.
455
- * See https://reactjs.org/docs/react-api.html#createfactory
456
- */
457
-export function createFactory(type) {
458
- const factory = createElement.bind(null, type);
459
- // Expose the type on the factory and the prototype so that it can be
460
- // easily accessed on elements. E.g. `<Foo />.type === Foo`.
461
- // This should not be named `constructor` since this may not be the function
462
- // that created the element, and it may not even be a constructor.
463
- // Legacy hook: remove it
464
- factory.type = type;
465
- return factory;
466
-}
467
-
468
-export function cloneAndReplaceKey(oldElement, newKey) {
469
- const newElement = ReactElement(
470
- oldElement.type,
471
- newKey,
472
- oldElement.ref,
473
- oldElement._self,
474
- oldElement._source,
475
- oldElement._owner,
476
- oldElement.props,
477
- );
478
-
479
- return newElement;
480
-}
481
-
482
-/**
483
- * Clone and return a new ReactElement using element as the starting point.
484
- * See https://reactjs.org/docs/react-api.html#cloneelement
485
- */
486
-export function cloneElement(element, config, children) {
487
- if (element === null || element === undefined) {
488
- throw new Error(
489
- `React.cloneElement(...): The argument must be a React element, but you passed ${element}.`,
490
- );
491
- }
492
-
493
- let propName;
494
-
495
- // Original props are copied
496
- const props = assign({}, element.props);
497
-
498
- // Reserved names are extracted
499
- let key = element.key;
500
- let ref = element.ref;
501
- // Self is preserved since the owner is preserved.
502
- const self = element._self;
503
- // Source is preserved since cloneElement is unlikely to be targeted by a
504
- // transpiler, and the original source is probably a better indicator of the
505
- // true owner.
506
- const source = element._source;
507
-
508
- // Owner will be preserved, unless ref is overridden
509
- let owner = element._owner;
510
-
511
- if (config != null) {
512
- if (hasValidRef(config)) {
513
- // Silently steal the ref from the parent.
514
- ref = config.ref;
515
- owner = ReactCurrentOwner.current;
516
- }
517
- if (hasValidKey(config)) {
518
- if (__DEV__) {
519
- checkKeyStringCoercion(config.key);
520
- }
521
- key = '' + config.key;
522
- }
523
-
524
- // Remaining properties override existing props
525
- let defaultProps;
526
- if (element.type && element.type.defaultProps) {
527
- defaultProps = element.type.defaultProps;
528
- }
529
- for (propName in config) {
530
- if (
531
- hasOwnProperty.call(config, propName) &&
532
- !RESERVED_PROPS.hasOwnProperty(propName)
533
- ) {
534
- if (config[propName] === undefined && defaultProps !== undefined) {
535
- // Resolve default props
536
- props[propName] = defaultProps[propName];
537
- } else {
538
- props[propName] = config[propName];
539
- }
540
- }
541
- }
542
- }
543
-
544
- // Children can be more than one argument, and those are transferred onto
545
- // the newly allocated props object.
546
- const childrenLength = arguments.length - 2;
547
- if (childrenLength === 1) {
548
- props.children = children;
549
- } else if (childrenLength > 1) {
550
- const childArray = Array(childrenLength);
551
- for (let i = 0; i < childrenLength; i++) {
552
- childArray[i] = arguments[i + 2];
553
- }
554
- props.children = childArray;
555
- }
556
-
557
- return ReactElement(element.type, key, ref, self, source, owner, props);
558
-}
559
-
560
-/**
561
- * Verifies the object is a ReactElement.
562
- * See https://reactjs.org/docs/react-api.html#isvalidelement
563
- * @param {?object} object
564
- * @return {boolean} True if `object` is a ReactElement.
565
- * @final
566
- */
567
-export function isValidElement(object) {
568
- return (
569
- typeof object === 'object' &&
570
- object !== null &&
571
- object.$$typeof === REACT_ELEMENT_TYPE
572
- );
573
-}
7
+ * @flow
8
+ */
9
+
10
+import {
11
+ createElement as createElementProd,
12
+ createFactory as createFactoryProd,
13
+ cloneElement as cloneElementProd,
14
+} from './ReactElementProd';
15
+
16
+import {
17
+ createElementWithValidation,
18
+ createFactoryWithValidation,
19
+ cloneElementWithValidation,
20
+} from './ReactElementValidator';
21
+
22
+export {isValidElement, cloneAndReplaceKey} from './ReactElementProd';
23
+
24
+export const createElement: any = __DEV__
25
+ ? createElementWithValidation
26
+ : createElementProd;
27
+export const cloneElement: any = __DEV__
28
+ ? cloneElementWithValidation
29
+ : cloneElementProd;
30
+export const createFactory: any = __DEV__
31
+ ? createFactoryWithValidation
32
+ : createFactoryProd;
packages/react/src/ReactElementProd.js
new
+573
@@ -0,0 +1,573 @@
1
+/**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+import getComponentNameFromType from 'shared/getComponentNameFromType';
9
+import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
10
+import assign from 'shared/assign';
11
+import hasOwnProperty from 'shared/hasOwnProperty';
12
+import {checkKeyStringCoercion} from 'shared/CheckStringCoercion';
13
+
14
+import ReactCurrentOwner from './ReactCurrentOwner';
15
+
16
+const RESERVED_PROPS = {
17
+ key: true,
18
+ ref: true,
19
+ __self: true,
20
+ __source: true,
21
+};
22
+
23
+let specialPropKeyWarningShown,
24
+ specialPropRefWarningShown,
25
+ didWarnAboutStringRefs;
26
+
27
+if (__DEV__) {
28
+ didWarnAboutStringRefs = {};
29
+}
30
+
31
+function hasValidRef(config) {
32
+ if (__DEV__) {
33
+ if (hasOwnProperty.call(config, 'ref')) {
34
+ const getter = Object.getOwnPropertyDescriptor(config, 'ref').get;
35
+ if (getter && getter.isReactWarning) {
36
+ return false;
37
+ }
38
+ }
39
+ }
40
+ return config.ref !== undefined;
41
+}
42
+
43
+function hasValidKey(config) {
44
+ if (__DEV__) {
45
+ if (hasOwnProperty.call(config, 'key')) {
46
+ const getter = Object.getOwnPropertyDescriptor(config, 'key').get;
47
+ if (getter && getter.isReactWarning) {
48
+ return false;
49
+ }
50
+ }
51
+ }
52
+ return config.key !== undefined;
53
+}
54
+
55
+function defineKeyPropWarningGetter(props, displayName) {
56
+ const warnAboutAccessingKey = function () {
57
+ if (__DEV__) {
58
+ if (!specialPropKeyWarningShown) {
59
+ specialPropKeyWarningShown = true;
60
+ console.error(
61
+ '%s: `key` is not a prop. Trying to access it will result ' +
62
+ 'in `undefined` being returned. If you need to access the same ' +
63
+ 'value within the child component, you should pass it as a different ' +
64
+ 'prop. (https://reactjs.org/link/special-props)',
65
+ displayName,
66
+ );
67
+ }
68
+ }
69
+ };
70
+ warnAboutAccessingKey.isReactWarning = true;
71
+ Object.defineProperty(props, 'key', {
72
+ get: warnAboutAccessingKey,
73
+ configurable: true,
74
+ });
75
+}
76
+
77
+function defineRefPropWarningGetter(props, displayName) {
78
+ const warnAboutAccessingRef = function () {
79
+ if (__DEV__) {
80
+ if (!specialPropRefWarningShown) {
81
+ specialPropRefWarningShown = true;
82
+ console.error(
83
+ '%s: `ref` is not a prop. Trying to access it will result ' +
84
+ 'in `undefined` being returned. If you need to access the same ' +
85
+ 'value within the child component, you should pass it as a different ' +
86
+ 'prop. (https://reactjs.org/link/special-props)',
87
+ displayName,
88
+ );
89
+ }
90
+ }
91
+ };
92
+ warnAboutAccessingRef.isReactWarning = true;
93
+ Object.defineProperty(props, 'ref', {
94
+ get: warnAboutAccessingRef,
95
+ configurable: true,
96
+ });
97
+}
98
+
99
+function warnIfStringRefCannotBeAutoConverted(config) {
100
+ if (__DEV__) {
101
+ if (
102
+ typeof config.ref === 'string' &&
103
+ ReactCurrentOwner.current &&
104
+ config.__self &&
105
+ ReactCurrentOwner.current.stateNode !== config.__self
106
+ ) {
107
+ const componentName = getComponentNameFromType(
108
+ ReactCurrentOwner.current.type,
109
+ );
110
+
111
+ if (!didWarnAboutStringRefs[componentName]) {
112
+ console.error(
113
+ 'Component "%s" contains the string ref "%s". ' +
114
+ 'Support for string refs will be removed in a future major release. ' +
115
+ 'This case cannot be automatically converted to an arrow function. ' +
116
+ 'We ask you to manually fix this case by using useRef() or createRef() instead. ' +
117
+ 'Learn more about using refs safely here: ' +
118
+ 'https://reactjs.org/link/strict-mode-string-ref',
119
+ componentName,
120
+ config.ref,
121
+ );
122
+ didWarnAboutStringRefs[componentName] = true;
123
+ }
124
+ }
125
+ }
126
+}
127
+
128
+/**
129
+ * Factory method to create a new React element. This no longer adheres to
130
+ * the class pattern, so do not use new to call it. Also, instanceof check
131
+ * will not work. Instead test $$typeof field against Symbol.for('react.element') to check
132
+ * if something is a React Element.
133
+ *
134
+ * @param {*} type
135
+ * @param {*} props
136
+ * @param {*} key
137
+ * @param {string|object} ref
138
+ * @param {*} owner
139
+ * @param {*} self A *temporary* helper to detect places where `this` is
140
+ * different from the `owner` when React.createElement is called, so that we
141
+ * can warn. We want to get rid of owner and replace string `ref`s with arrow
142
+ * functions, and as long as `this` and owner are the same, there will be no
143
+ * change in behavior.
144
+ * @param {*} source An annotation object (added by a transpiler or otherwise)
145
+ * indicating filename, line number, and/or other information.
146
+ * @internal
147
+ */
148
+function ReactElement(type, key, ref, self, source, owner, props) {
149
+ const element = {
150
+ // This tag allows us to uniquely identify this as a React Element
151
+ $$typeof: REACT_ELEMENT_TYPE,
152
+
153
+ // Built-in properties that belong on the element
154
+ type: type,
155
+ key: key,
156
+ ref: ref,
157
+ props: props,
158
+
159
+ // Record the component responsible for creating this element.
160
+ _owner: owner,
161
+ };
162
+
163
+ if (__DEV__) {
164
+ // The validation flag is currently mutative. We put it on
165
+ // an external backing store so that we can freeze the whole object.
166
+ // This can be replaced with a WeakMap once they are implemented in
167
+ // commonly used development environments.
168
+ element._store = {};
169
+
170
+ // To make comparing ReactElements easier for testing purposes, we make
171
+ // the validation flag non-enumerable (where possible, which should
172
+ // include every environment we run tests in), so the test framework
173
+ // ignores it.
174
+ Object.defineProperty(element._store, 'validated', {
175
+ configurable: false,
176
+ enumerable: false,
177
+ writable: true,
178
+ value: false,
179
+ });
180
+ // self and source are DEV only properties.
181
+ Object.defineProperty(element, '_self', {
182
+ configurable: false,
183
+ enumerable: false,
184
+ writable: false,
185
+ value: self,
186
+ });
187
+ // Two elements created in two different places should be considered
188
+ // equal for testing purposes and therefore we hide it from enumeration.
189
+ Object.defineProperty(element, '_source', {
190
+ configurable: false,
191
+ enumerable: false,
192
+ writable: false,
193
+ value: source,
194
+ });
195
+ if (Object.freeze) {
196
+ Object.freeze(element.props);
197
+ Object.freeze(element);
198
+ }
199
+ }
200
+
201
+ return element;
202
+}
203
+
204
+/**
205
+ * https://github.com/reactjs/rfcs/pull/107
206
+ * @param {*} type
207
+ * @param {object} props
208
+ * @param {string} key
209
+ */
210
+export function jsx(type, config, maybeKey) {
211
+ let propName;
212
+
213
+ // Reserved names are extracted
214
+ const props = {};
215
+
216
+ let key = null;
217
+ let ref = null;
218
+
219
+ // Currently, key can be spread in as a prop. This causes a potential
220
+ // issue if key is also explicitly declared (ie. <div {...props} key="Hi" />
221
+ // or <div key="Hi" {...props} /> ). We want to deprecate key spread,
222
+ // but as an intermediary step, we will use jsxDEV for everything except
223
+ // <div {...props} key="Hi" />, because we aren't currently able to tell if
224
+ // key is explicitly declared to be undefined or not.
225
+ if (maybeKey !== undefined) {
226
+ if (__DEV__) {
227
+ checkKeyStringCoercion(maybeKey);
228
+ }
229
+ key = '' + maybeKey;
230
+ }
231
+
232
+ if (hasValidKey(config)) {
233
+ if (__DEV__) {
234
+ checkKeyStringCoercion(config.key);
235
+ }
236
+ key = '' + config.key;
237
+ }
238
+
239
+ if (hasValidRef(config)) {
240
+ ref = config.ref;
241
+ }
242
+
243
+ // Remaining properties are added to a new props object
244
+ for (propName in config) {
245
+ if (
246
+ hasOwnProperty.call(config, propName) &&
247
+ !RESERVED_PROPS.hasOwnProperty(propName)
248
+ ) {
249
+ props[propName] = config[propName];
250
+ }
251
+ }
252
+
253
+ // Resolve default props
254
+ if (type && type.defaultProps) {
255
+ const defaultProps = type.defaultProps;
256
+ for (propName in defaultProps) {
257
+ if (props[propName] === undefined) {
258
+ props[propName] = defaultProps[propName];
259
+ }
260
+ }
261
+ }
262
+
263
+ return ReactElement(
264
+ type,
265
+ key,
266
+ ref,
267
+ undefined,
268
+ undefined,
269
+ ReactCurrentOwner.current,
270
+ props,
271
+ );
272
+}
273
+
274
+/**
275
+ * https://github.com/reactjs/rfcs/pull/107
276
+ * @param {*} type
277
+ * @param {object} props
278
+ * @param {string} key
279
+ */
280
+export function jsxDEV(type, config, maybeKey, source, self) {
281
+ let propName;
282
+
283
+ // Reserved names are extracted
284
+ const props = {};
285
+
286
+ let key = null;
287
+ let ref = null;
288
+
289
+ // Currently, key can be spread in as a prop. This causes a potential
290
+ // issue if key is also explicitly declared (ie. <div {...props} key="Hi" />
291
+ // or <div key="Hi" {...props} /> ). We want to deprecate key spread,
292
+ // but as an intermediary step, we will use jsxDEV for everything except
293
+ // <div {...props} key="Hi" />, because we aren't currently able to tell if
294
+ // key is explicitly declared to be undefined or not.
295
+ if (maybeKey !== undefined) {
296
+ if (__DEV__) {
297
+ checkKeyStringCoercion(maybeKey);
298
+ }
299
+ key = '' + maybeKey;
300
+ }
301
+
302
+ if (hasValidKey(config)) {
303
+ if (__DEV__) {
304
+ checkKeyStringCoercion(config.key);
305
+ }
306
+ key = '' + config.key;
307
+ }
308
+
309
+ if (hasValidRef(config)) {
310
+ ref = config.ref;
311
+ warnIfStringRefCannotBeAutoConverted(config);
312
+ }
313
+
314
+ // Remaining properties are added to a new props object
315
+ for (propName in config) {
316
+ if (
317
+ hasOwnProperty.call(config, propName) &&
318
+ !RESERVED_PROPS.hasOwnProperty(propName)
319
+ ) {
320
+ props[propName] = config[propName];
321
+ }
322
+ }
323
+
324
+ // Resolve default props
325
+ if (type && type.defaultProps) {
326
+ const defaultProps = type.defaultProps;
327
+ for (propName in defaultProps) {
328
+ if (props[propName] === undefined) {
329
+ props[propName] = defaultProps[propName];
330
+ }
331
+ }
332
+ }
333
+
334
+ if (key || ref) {
335
+ const displayName =
336
+ typeof type === 'function'
337
+ ? type.displayName || type.name || 'Unknown'
338
+ : type;
339
+ if (key) {
340
+ defineKeyPropWarningGetter(props, displayName);
341
+ }
342
+ if (ref) {
343
+ defineRefPropWarningGetter(props, displayName);
344
+ }
345
+ }
346
+
347
+ return ReactElement(
348
+ type,
349
+ key,
350
+ ref,
351
+ self,
352
+ source,
353
+ ReactCurrentOwner.current,
354
+ props,
355
+ );
356
+}
357
+
358
+/**
359
+ * Create and return a new ReactElement of the given type.
360
+ * See https://reactjs.org/docs/react-api.html#createelement
361
+ */
362
+export function createElement(type, config, children) {
363
+ let propName;
364
+
365
+ // Reserved names are extracted
366
+ const props = {};
367
+
368
+ let key = null;
369
+ let ref = null;
370
+ let self = null;
371
+ let source = null;
372
+
373
+ if (config != null) {
374
+ if (hasValidRef(config)) {
375
+ ref = config.ref;
376
+
377
+ if (__DEV__) {
378
+ warnIfStringRefCannotBeAutoConverted(config);
379
+ }
380
+ }
381
+ if (hasValidKey(config)) {
382
+ if (__DEV__) {
383
+ checkKeyStringCoercion(config.key);
384
+ }
385
+ key = '' + config.key;
386
+ }
387
+
388
+ self = config.__self === undefined ? null : config.__self;
389
+ source = config.__source === undefined ? null : config.__source;
390
+ // Remaining properties are added to a new props object
391
+ for (propName in config) {
392
+ if (
393
+ hasOwnProperty.call(config, propName) &&
394
+ !RESERVED_PROPS.hasOwnProperty(propName)
395
+ ) {
396
+ props[propName] = config[propName];
397
+ }
398
+ }
399
+ }
400
+
401
+ // Children can be more than one argument, and those are transferred onto
402
+ // the newly allocated props object.
403
+ const childrenLength = arguments.length - 2;
404
+ if (childrenLength === 1) {
405
+ props.children = children;
406
+ } else if (childrenLength > 1) {
407
+ const childArray = Array(childrenLength);
408
+ for (let i = 0; i < childrenLength; i++) {
409
+ childArray[i] = arguments[i + 2];
410
+ }
411
+ if (__DEV__) {
412
+ if (Object.freeze) {
413
+ Object.freeze(childArray);
414
+ }
415
+ }
416
+ props.children = childArray;
417
+ }
418
+
419
+ // Resolve default props
420
+ if (type && type.defaultProps) {
421
+ const defaultProps = type.defaultProps;
422
+ for (propName in defaultProps) {
423
+ if (props[propName] === undefined) {
424
+ props[propName] = defaultProps[propName];
425
+ }
426
+ }
427
+ }
428
+ if (__DEV__) {
429
+ if (key || ref) {
430
+ const displayName =
431
+ typeof type === 'function'
432
+ ? type.displayName || type.name || 'Unknown'
433
+ : type;
434
+ if (key) {
435
+ defineKeyPropWarningGetter(props, displayName);
436
+ }
437
+ if (ref) {
438
+ defineRefPropWarningGetter(props, displayName);
439
+ }
440
+ }
441
+ }
442
+ return ReactElement(
443
+ type,
444
+ key,
445
+ ref,
446
+ self,
447
+ source,
448
+ ReactCurrentOwner.current,
449
+ props,
450
+ );
451
+}
452
+
453
+/**
454
+ * Return a function that produces ReactElements of a given type.
455
+ * See https://reactjs.org/docs/react-api.html#createfactory
456
+ */
457
+export function createFactory(type) {
458
+ const factory = createElement.bind(null, type);
459
+ // Expose the type on the factory and the prototype so that it can be
460
+ // easily accessed on elements. E.g. `<Foo />.type === Foo`.
461
+ // This should not be named `constructor` since this may not be the function
462
+ // that created the element, and it may not even be a constructor.
463
+ // Legacy hook: remove it
464
+ factory.type = type;
465
+ return factory;
466
+}
467
+
468
+export function cloneAndReplaceKey(oldElement, newKey) {
469
+ const newElement = ReactElement(
470
+ oldElement.type,
471
+ newKey,
472
+ oldElement.ref,
473
+ oldElement._self,
474
+ oldElement._source,
475
+ oldElement._owner,
476
+ oldElement.props,
477
+ );
478
+
479
+ return newElement;
480
+}
481
+
482
+/**
483
+ * Clone and return a new ReactElement using element as the starting point.
484
+ * See https://reactjs.org/docs/react-api.html#cloneelement
485
+ */
486
+export function cloneElement(element, config, children) {
487
+ if (element === null || element === undefined) {
488
+ throw new Error(
489
+ `React.cloneElement(...): The argument must be a React element, but you passed ${element}.`,
490
+ );
491
+ }
492
+
493
+ let propName;
494
+
495
+ // Original props are copied
496
+ const props = assign({}, element.props);
497
+
498
+ // Reserved names are extracted
499
+ let key = element.key;
500
+ let ref = element.ref;
501
+ // Self is preserved since the owner is preserved.
502
+ const self = element._self;
503
+ // Source is preserved since cloneElement is unlikely to be targeted by a
504
+ // transpiler, and the original source is probably a better indicator of the
505
+ // true owner.
506
+ const source = element._source;
507
+
508
+ // Owner will be preserved, unless ref is overridden
509
+ let owner = element._owner;
510
+
511
+ if (config != null) {
512
+ if (hasValidRef(config)) {
513
+ // Silently steal the ref from the parent.
514
+ ref = config.ref;
515
+ owner = ReactCurrentOwner.current;
516
+ }
517
+ if (hasValidKey(config)) {
518
+ if (__DEV__) {
519
+ checkKeyStringCoercion(config.key);
520
+ }
521
+ key = '' + config.key;
522
+ }
523
+
524
+ // Remaining properties override existing props
525
+ let defaultProps;
526
+ if (element.type && element.type.defaultProps) {
527
+ defaultProps = element.type.defaultProps;
528
+ }
529
+ for (propName in config) {
530
+ if (
531
+ hasOwnProperty.call(config, propName) &&
532
+ !RESERVED_PROPS.hasOwnProperty(propName)
533
+ ) {
534
+ if (config[propName] === undefined && defaultProps !== undefined) {
535
+ // Resolve default props
536
+ props[propName] = defaultProps[propName];
537
+ } else {
538
+ props[propName] = config[propName];
539
+ }
540
+ }
541
+ }
542
+ }
543
+
544
+ // Children can be more than one argument, and those are transferred onto
545
+ // the newly allocated props object.
546
+ const childrenLength = arguments.length - 2;
547
+ if (childrenLength === 1) {
548
+ props.children = children;
549
+ } else if (childrenLength > 1) {
550
+ const childArray = Array(childrenLength);
551
+ for (let i = 0; i < childrenLength; i++) {
552
+ childArray[i] = arguments[i + 2];
553
+ }
554
+ props.children = childArray;
555
+ }
556
+
557
+ return ReactElement(element.type, key, ref, self, source, owner, props);
558
+}
559
+
560
+/**
561
+ * Verifies the object is a ReactElement.
562
+ * See https://reactjs.org/docs/react-api.html#isvalidelement
563
+ * @param {?object} object
564
+ * @return {boolean} True if `object` is a ReactElement.
565
+ * @final
566
+ */
567
+export function isValidElement(object) {
568
+ return (
569
+ typeof object === 'object' &&
570
+ object !== null &&
571
+ object.$$typeof === REACT_ELEMENT_TYPE
572
+ );
573
+}
packages/react/src/ReactElementValidator.js
+1
-1
@@ -30,7 +30,7 @@ import {
30
createElement,
31
cloneElement,
32
jsxDEV,
33
-} from './ReactElement';
33
+} from './ReactElementProd';
34
import {setExtraStackFrame} from './ReactDebugCurrentFrame';
35
import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
36
import hasOwnProperty from 'shared/hasOwnProperty';
packages/react/src/ReactServer.experimental.js
+47
-10
@@ -14,6 +14,43 @@ export {default as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './R
14
15
export {default as __SECRET_SERVER_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './ReactServerSharedInternals';
16
17
+import {forEach, map, count, toArray, only} from './ReactChildren';
18
+import {
19
+ REACT_FRAGMENT_TYPE,
20
+ REACT_PROFILER_TYPE,
21
+ REACT_STRICT_MODE_TYPE,
22
+ REACT_SUSPENSE_TYPE,
23
+ REACT_DEBUG_TRACING_MODE_TYPE,
24
+} from 'shared/ReactSymbols';
25
+import {cloneElement, createElement, isValidElement} from './ReactElement';
26
+import {createRef} from './ReactCreateRef';
27
+import {createServerContext} from './ReactServerContext';
28
+import {
29
+ use,
30
+ useId,
31
+ useCallback,
32
+ useContext,
33
+ useDebugValue,
34
+ useMemo,
35
+ getCacheSignal,
36
+ getCacheForType,
37
+} from './ReactHooks';
38
+import {forwardRef} from './ReactForwardRef';
39
+import {lazy} from './ReactLazy';
40
+import {memo} from './ReactMemo';
41
+import {cache} from './ReactCache';
42
+import {startTransition} from './ReactStartTransition';
43
+import {postpone} from './ReactPostpone';
44
+import version from 'shared/ReactVersion';
45
+
46
+const Children = {
47
+ map,
48
+ forEach,
49
+ count,
50
+ toArray,
51
+ only,
52
+};
53
+
54
// These are server-only
55
export {
56
taintUniqueValue as experimental_taintUniqueValue,
@@ -22,10 +59,10 @@ export {
59
60
export {
61
Children,
25
- Fragment,
26
- Profiler,
27
- StrictMode,
28
- Suspense,
62
+ REACT_FRAGMENT_TYPE as Fragment,
63
+ REACT_PROFILER_TYPE as Profiler,
64
+ REACT_STRICT_MODE_TYPE as StrictMode,
65
+ REACT_SUSPENSE_TYPE as Suspense,
66
cloneElement,
67
createElement,
68
createRef,
@@ -37,15 +74,15 @@ export {
74
memo,
75
cache,
76
startTransition,
40
- unstable_DebugTracingMode,
41
- unstable_SuspenseList,
42
- unstable_getCacheSignal,
43
- unstable_getCacheForType,
44
- unstable_postpone,
77
+ REACT_DEBUG_TRACING_MODE_TYPE as unstable_DebugTracingMode,
78
+ REACT_SUSPENSE_TYPE as unstable_SuspenseList,
79
+ getCacheSignal as unstable_getCacheSignal,
80
+ getCacheForType as unstable_getCacheForType,
81
+ postpone as unstable_postpone,
82
useId,
83
useCallback,
84
useContext,
85
useDebugValue,
86
useMemo,
87
version,
51
-} from './React';
88
+};
packages/react/src/ReactServer.js
+38
-5
@@ -14,12 +14,45 @@ export {default as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './R
14
15
export {default as __SECRET_SERVER_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './ReactServerSharedInternals';
16
17
+import {forEach, map, count, toArray, only} from './ReactChildren';
18
+import {
19
+ REACT_FRAGMENT_TYPE,
20
+ REACT_PROFILER_TYPE,
21
+ REACT_STRICT_MODE_TYPE,
22
+ REACT_SUSPENSE_TYPE,
23
+} from 'shared/ReactSymbols';
24
+import {cloneElement, createElement, isValidElement} from './ReactElement';
25
+import {createRef} from './ReactCreateRef';
26
+import {createServerContext} from './ReactServerContext';
27
+import {
28
+ use,
29
+ useId,
30
+ useCallback,
31
+ useContext,
32
+ useDebugValue,
33
+ useMemo,
34
+} from './ReactHooks';
35
+import {forwardRef} from './ReactForwardRef';
36
+import {lazy} from './ReactLazy';
37
+import {memo} from './ReactMemo';
38
+import {cache} from './ReactCache';
39
+import {startTransition} from './ReactStartTransition';
40
+import version from 'shared/ReactVersion';
41
+
42
+const Children = {
43
+ map,
44
+ forEach,
45
+ count,
46
+ toArray,
47
+ only,
48
+};
49
+
50
export {
51
Children,
19
- Fragment,
20
- Profiler,
21
- StrictMode,
22
- Suspense,
52
+ REACT_FRAGMENT_TYPE as Fragment,
53
+ REACT_PROFILER_TYPE as Profiler,
54
+ REACT_STRICT_MODE_TYPE as StrictMode,
55
+ REACT_SUSPENSE_TYPE as Suspense,
56
cloneElement,
57
createElement,
58
createRef,
@@ -37,4 +70,4 @@ export {
70
useDebugValue,
71
useMemo,
72
version,
40
-} from './React';
73
+};