@samitouri / QOS-React-1 / commits / f16344ea6d

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 +};