Replace ReactShallowRenderer with a dependency (#18144)
Closes #17321.
Minh Nguyen committed
Feb 27, 2020 at 18:10 UTC
293878e079b170670b08449bfdcd7aebaa6afbc2
4 files changed
+11
-864
packages/react-test-renderer/package.json
+1
@@ -22,6 +22,7 @@
22
"object-assign": "^4.1.1",
23
"prop-types": "^15.6.2",
24
"react-is": "^16.8.6",
25
+ "react-shallow-renderer": "^16.12.0",
26
"scheduler": "^0.19.0"
27
},
28
"peerDependencies": {
packages/react-test-renderer/shallow.js
+1
-1
@@ -7,4 +7,4 @@
7
* @flow
8
*/
9
10
-export {default} from './src/ReactShallowRenderer';
10
+export {default} from 'react-shallow-renderer';
packages/react-test-renderer/src/ReactShallowRenderer.js
deleted
-863
@@ -1,863 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its 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
- * @flow
8
- */
9
-
10
-import * as React from 'react';
11
-import {isForwardRef, isMemo, ForwardRef} from 'react-is';
12
-import describeComponentFrame from 'shared/describeComponentFrame';
13
-import getComponentName from 'shared/getComponentName';
14
-import shallowEqual from 'shared/shallowEqual';
15
-import invariant from 'shared/invariant';
16
-import checkPropTypes from 'prop-types/checkPropTypes';
17
-import ReactSharedInternals from 'shared/ReactSharedInternals';
18
-import is from 'shared/objectIs';
19
-
20
-import type {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactFiberHooks';
21
-import type {
22
- ReactContext,
23
- ReactEventResponderListener,
24
-} from 'shared/ReactTypes';
25
-import type {ReactElement} from 'shared/ReactElementType';
26
-
27
-type BasicStateAction<S> = (S => S) | S;
28
-type Dispatch<A> = A => void;
29
-
30
-type Update<A> = {|
31
- action: A,
32
- next: Update<A> | null,
33
-|};
34
-
35
-type UpdateQueue<A> = {|
36
- first: Update<A> | null,
37
- dispatch: any,
38
-|};
39
-
40
-type Hook = {|
41
- memoizedState: any,
42
- queue: UpdateQueue<any> | null,
43
- next: Hook | null,
44
-|};
45
-
46
-const {ReactCurrentDispatcher} = ReactSharedInternals;
47
-
48
-const RE_RENDER_LIMIT = 25;
49
-
50
-const emptyObject = {};
51
-if (__DEV__) {
52
- Object.freeze(emptyObject);
53
-}
54
-
55
-// In DEV, this is the name of the currently executing primitive hook
56
-let currentHookNameInDev: ?string;
57
-
58
-function areHookInputsEqual(
59
- nextDeps: Array<mixed>,
60
- prevDeps: Array<mixed> | null,
61
-) {
62
- if (prevDeps === null) {
63
- if (__DEV__) {
64
- console.error(
65
- '%s received a final argument during this render, but not during ' +
66
- 'the previous render. Even though the final argument is optional, ' +
67
- 'its type cannot change between renders.',
68
- currentHookNameInDev,
69
- );
70
- }
71
- return false;
72
- }
73
-
74
- if (__DEV__) {
75
- // Don't bother comparing lengths in prod because these arrays should be
76
- // passed inline.
77
- if (nextDeps.length !== prevDeps.length) {
78
- console.error(
79
- 'The final argument passed to %s changed size between renders. The ' +
80
- 'order and size of this array must remain constant.\n\n' +
81
- 'Previous: %s\n' +
82
- 'Incoming: %s',
83
- currentHookNameInDev,
84
- `[${nextDeps.join(', ')}]`,
85
- `[${prevDeps.join(', ')}]`,
86
- );
87
- }
88
- }
89
- for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
90
- if (is(nextDeps[i], prevDeps[i])) {
91
- continue;
92
- }
93
- return false;
94
- }
95
- return true;
96
-}
97
-
98
-class Updater {
99
- constructor(renderer) {
100
- this._renderer = renderer;
101
- this._callbacks = [];
102
- }
103
-
104
- _renderer: ReactShallowRenderer;
105
- _callbacks: Array<any>;
106
-
107
- _enqueueCallback(callback, publicInstance) {
108
- if (typeof callback === 'function' && publicInstance) {
109
- this._callbacks.push({
110
- callback,
111
- publicInstance,
112
- });
113
- }
114
- }
115
-
116
- _invokeCallbacks() {
117
- const callbacks = this._callbacks;
118
- this._callbacks = [];
119
-
120
- callbacks.forEach(({callback, publicInstance}) => {
121
- callback.call(publicInstance);
122
- });
123
- }
124
-
125
- isMounted(publicInstance) {
126
- return !!this._renderer._element;
127
- }
128
-
129
- enqueueForceUpdate(publicInstance, callback, callerName) {
130
- this._enqueueCallback(callback, publicInstance);
131
- this._renderer._forcedUpdate = true;
132
- this._renderer.render(this._renderer._element, this._renderer._context);
133
- }
134
-
135
- enqueueReplaceState(publicInstance, completeState, callback, callerName) {
136
- this._enqueueCallback(callback, publicInstance);
137
- this._renderer._newState = completeState;
138
- this._renderer.render(this._renderer._element, this._renderer._context);
139
- }
140
-
141
- enqueueSetState(publicInstance, partialState, callback, callerName) {
142
- this._enqueueCallback(callback, publicInstance);
143
- const currentState = this._renderer._newState || publicInstance.state;
144
-
145
- if (typeof partialState === 'function') {
146
- partialState = partialState.call(
147
- publicInstance,
148
- currentState,
149
- publicInstance.props,
150
- );
151
- }
152
-
153
- // Null and undefined are treated as no-ops.
154
- if (partialState === null || partialState === undefined) {
155
- return;
156
- }
157
-
158
- this._renderer._newState = {
159
- ...currentState,
160
- ...partialState,
161
- };
162
-
163
- this._renderer.render(this._renderer._element, this._renderer._context);
164
- }
165
-}
166
-
167
-function createHook(): Hook {
168
- return {
169
- memoizedState: null,
170
- queue: null,
171
- next: null,
172
- };
173
-}
174
-
175
-function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S {
176
- // $FlowFixMe: Flow doesn't like mixed types
177
- return typeof action === 'function' ? action(state) : action;
178
-}
179
-
180
-class ReactShallowRenderer {
181
- static createRenderer = function() {
182
- return new ReactShallowRenderer();
183
- };
184
-
185
- constructor() {
186
- this._reset();
187
- }
188
-
189
- _reset() {
190
- this._context = null;
191
- this._element = null;
192
- this._instance = null;
193
- this._newState = null;
194
- this._rendered = null;
195
- this._rendering = false;
196
- this._forcedUpdate = false;
197
- this._updater = new Updater(this);
198
- this._dispatcher = this._createDispatcher();
199
- this._workInProgressHook = null;
200
- this._firstWorkInProgressHook = null;
201
- this._isReRender = false;
202
- this._didScheduleRenderPhaseUpdate = false;
203
- this._renderPhaseUpdates = null;
204
- this._numberOfReRenders = 0;
205
- }
206
-
207
- _context: null | Object;
208
- _newState: null | Object;
209
- _instance: any;
210
- _element: null | ReactElement;
211
- _rendered: null | mixed;
212
- _updater: Updater;
213
- _rendering: boolean;
214
- _forcedUpdate: boolean;
215
- _dispatcher: DispatcherType;
216
- _workInProgressHook: null | Hook;
217
- _firstWorkInProgressHook: null | Hook;
218
- _renderPhaseUpdates: Map<UpdateQueue<any>, Update<any>> | null;
219
- _isReRender: boolean;
220
- _didScheduleRenderPhaseUpdate: boolean;
221
- _numberOfReRenders: number;
222
-
223
- _validateCurrentlyRenderingComponent() {
224
- invariant(
225
- this._rendering && !this._instance,
226
- 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
227
- ' one of the following reasons:\n' +
228
- '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
229
- '2. You might be breaking the Rules of Hooks\n' +
230
- '3. You might have more than one copy of React in the same app\n' +
231
- 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.',
232
- );
233
- }
234
-
235
- _createDispatcher(): DispatcherType {
236
- const useReducer = <S, I, A>(
237
- reducer: (S, A) => S,
238
- initialArg: I,
239
- init?: I => S,
240
- ): [S, Dispatch<A>] => {
241
- this._validateCurrentlyRenderingComponent();
242
- this._createWorkInProgressHook();
243
- const workInProgressHook: Hook = (this._workInProgressHook: any);
244
-
245
- if (this._isReRender) {
246
- // This is a re-render.
247
- const queue: UpdateQueue<A> = (workInProgressHook.queue: any);
248
- const dispatch: Dispatch<A> = (queue.dispatch: any);
249
- if (this._numberOfReRenders > 0) {
250
- // Apply the new render phase updates to the previous current hook.
251
- if (this._renderPhaseUpdates !== null) {
252
- // Render phase updates are stored in a map of queue -> linked list
253
- const firstRenderPhaseUpdate = this._renderPhaseUpdates.get(queue);
254
- if (firstRenderPhaseUpdate !== undefined) {
255
- (this._renderPhaseUpdates: any).delete(queue);
256
- let newState = workInProgressHook.memoizedState;
257
- let update = firstRenderPhaseUpdate;
258
- do {
259
- const action = update.action;
260
- newState = reducer(newState, action);
261
- update = update.next;
262
- } while (update !== null);
263
- workInProgressHook.memoizedState = newState;
264
- return [newState, dispatch];
265
- }
266
- }
267
- return [workInProgressHook.memoizedState, dispatch];
268
- }
269
- // Process updates outside of render
270
- let newState = workInProgressHook.memoizedState;
271
- let update = queue.first;
272
- if (update !== null) {
273
- do {
274
- const action = update.action;
275
- newState = reducer(newState, action);
276
- update = update.next;
277
- } while (update !== null);
278
- queue.first = null;
279
- workInProgressHook.memoizedState = newState;
280
- }
281
- return [newState, dispatch];
282
- } else {
283
- let initialState;
284
- if (reducer === basicStateReducer) {
285
- // Special case for `useState`.
286
- initialState =
287
- typeof initialArg === 'function'
288
- ? ((initialArg: any): () => S)()
289
- : ((initialArg: any): S);
290
- } else {
291
- initialState =
292
- init !== undefined ? init(initialArg) : ((initialArg: any): S);
293
- }
294
- workInProgressHook.memoizedState = initialState;
295
- const queue: UpdateQueue<A> = (workInProgressHook.queue = {
296
- first: null,
297
- dispatch: null,
298
- });
299
- const dispatch: Dispatch<A> = (queue.dispatch = (this._dispatchAction.bind(
300
- this,
301
- queue,
302
- ): any));
303
- return [workInProgressHook.memoizedState, dispatch];
304
- }
305
- };
306
-
307
- const useState = <S>(
308
- initialState: (() => S) | S,
309
- ): [S, Dispatch<BasicStateAction<S>>] => {
310
- return useReducer(
311
- basicStateReducer,
312
- // useReducer has a special case to support lazy useState initializers
313
- (initialState: any),
314
- );
315
- };
316
-
317
- const useMemo = <T>(
318
- nextCreate: () => T,
319
- deps: Array<mixed> | void | null,
320
- ): T => {
321
- this._validateCurrentlyRenderingComponent();
322
- this._createWorkInProgressHook();
323
-
324
- const nextDeps = deps !== undefined ? deps : null;
325
-
326
- if (
327
- this._workInProgressHook !== null &&
328
- this._workInProgressHook.memoizedState !== null
329
- ) {
330
- const prevState = this._workInProgressHook.memoizedState;
331
- const prevDeps = prevState[1];
332
- if (nextDeps !== null) {
333
- if (areHookInputsEqual(nextDeps, prevDeps)) {
334
- return prevState[0];
335
- }
336
- }
337
- }
338
-
339
- const nextValue = nextCreate();
340
- (this._workInProgressHook: any).memoizedState = [nextValue, nextDeps];
341
- return nextValue;
342
- };
343
-
344
- const useRef = <T>(initialValue: T): {|current: T|} => {
345
- this._validateCurrentlyRenderingComponent();
346
- this._createWorkInProgressHook();
347
- const previousRef = (this._workInProgressHook: any).memoizedState;
348
- if (previousRef === null) {
349
- const ref = {current: initialValue};
350
- if (__DEV__) {
351
- Object.seal(ref);
352
- }
353
- (this._workInProgressHook: any).memoizedState = ref;
354
- return ref;
355
- } else {
356
- return previousRef;
357
- }
358
- };
359
-
360
- const readContext = <T>(
361
- context: ReactContext<T>,
362
- observedBits: void | number | boolean,
363
- ): T => {
364
- return context._currentValue;
365
- };
366
-
367
- const noOp = () => {
368
- this._validateCurrentlyRenderingComponent();
369
- };
370
-
371
- const identity = (fn: Function): Function => {
372
- return fn;
373
- };
374
-
375
- const useResponder = (
376
- responder,
377
- props,
378
- ): ReactEventResponderListener<any, any> => ({
379
- props: props,
380
- responder,
381
- });
382
-
383
- // TODO: implement if we decide to keep the shallow renderer
384
- const useTransition = (
385
- config,
386
- ): [(callback: () => void) => void, boolean] => {
387
- this._validateCurrentlyRenderingComponent();
388
- const startTransition = callback => {
389
- callback();
390
- };
391
- return [startTransition, false];
392
- };
393
-
394
- // TODO: implement if we decide to keep the shallow renderer
395
- const useDeferredValue = <T>(value: T, config): T => {
396
- this._validateCurrentlyRenderingComponent();
397
- return value;
398
- };
399
-
400
- return {
401
- readContext,
402
- useCallback: (identity: any),
403
- useContext: <T>(context: ReactContext<T>): T => {
404
- this._validateCurrentlyRenderingComponent();
405
- return readContext(context);
406
- },
407
- useDebugValue: noOp,
408
- useEffect: noOp,
409
- useImperativeHandle: noOp,
410
- useLayoutEffect: noOp,
411
- useMemo,
412
- useReducer,
413
- useRef,
414
- useState,
415
- useResponder,
416
- useTransition,
417
- useDeferredValue,
418
- };
419
- }
420
-
421
- _dispatchAction<A>(queue: UpdateQueue<A>, action: A) {
422
- invariant(
423
- this._numberOfReRenders < RE_RENDER_LIMIT,
424
- 'Too many re-renders. React limits the number of renders to prevent ' +
425
- 'an infinite loop.',
426
- );
427
-
428
- if (this._rendering) {
429
- // This is a render phase update. Stash it in a lazily-created map of
430
- // queue -> linked list of updates. After this render pass, we'll restart
431
- // and apply the stashed updates on top of the work-in-progress hook.
432
- this._didScheduleRenderPhaseUpdate = true;
433
- const update: Update<A> = {
434
- action,
435
- next: null,
436
- };
437
- let renderPhaseUpdates = this._renderPhaseUpdates;
438
- if (renderPhaseUpdates === null) {
439
- this._renderPhaseUpdates = renderPhaseUpdates = new Map();
440
- }
441
- const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
442
- if (firstRenderPhaseUpdate === undefined) {
443
- renderPhaseUpdates.set(queue, update);
444
- } else {
445
- // Append the update to the end of the list.
446
- let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
447
- while (lastRenderPhaseUpdate.next !== null) {
448
- lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
449
- }
450
- lastRenderPhaseUpdate.next = update;
451
- }
452
- } else {
453
- const update: Update<A> = {
454
- action,
455
- next: null,
456
- };
457
-
458
- // Append the update to the end of the list.
459
- let last = queue.first;
460
- if (last === null) {
461
- queue.first = update;
462
- } else {
463
- while (last.next !== null) {
464
- last = last.next;
465
- }
466
- last.next = update;
467
- }
468
-
469
- // Re-render now.
470
- this.render(this._element, this._context);
471
- }
472
- }
473
-
474
- _createWorkInProgressHook(): Hook {
475
- if (this._workInProgressHook === null) {
476
- // This is the first hook in the list
477
- if (this._firstWorkInProgressHook === null) {
478
- this._isReRender = false;
479
- this._firstWorkInProgressHook = this._workInProgressHook = createHook();
480
- } else {
481
- // There's already a work-in-progress. Reuse it.
482
- this._isReRender = true;
483
- this._workInProgressHook = this._firstWorkInProgressHook;
484
- }
485
- } else {
486
- if (this._workInProgressHook.next === null) {
487
- this._isReRender = false;
488
- // Append to the end of the list
489
- this._workInProgressHook = (this
490
- ._workInProgressHook: any).next = createHook();
491
- } else {
492
- // There's already a work-in-progress. Reuse it.
493
- this._isReRender = true;
494
- this._workInProgressHook = this._workInProgressHook.next;
495
- }
496
- }
497
- return this._workInProgressHook;
498
- }
499
-
500
- _finishHooks(element: ReactElement, context: null | Object) {
501
- if (this._didScheduleRenderPhaseUpdate) {
502
- // Updates were scheduled during the render phase. They are stored in
503
- // the `renderPhaseUpdates` map. Call the component again, reusing the
504
- // work-in-progress hooks and applying the additional updates on top. Keep
505
- // restarting until no more updates are scheduled.
506
- this._didScheduleRenderPhaseUpdate = false;
507
- this._numberOfReRenders += 1;
508
-
509
- // Start over from the beginning of the list
510
- this._workInProgressHook = null;
511
- this._rendering = false;
512
- this.render(element, context);
513
- } else {
514
- this._workInProgressHook = null;
515
- this._renderPhaseUpdates = null;
516
- this._numberOfReRenders = 0;
517
- }
518
- }
519
-
520
- getMountedInstance() {
521
- return this._instance;
522
- }
523
-
524
- getRenderOutput() {
525
- return this._rendered;
526
- }
527
-
528
- render(element: ReactElement | null, context: null | Object = emptyObject) {
529
- invariant(
530
- React.isValidElement(element),
531
- 'ReactShallowRenderer render(): Invalid component element.%s',
532
- typeof element === 'function'
533
- ? ' Instead of passing a component class, make sure to instantiate ' +
534
- 'it by passing it to React.createElement.'
535
- : '',
536
- );
537
- element = ((element: any): ReactElement);
538
- // Show a special message for host elements since it's a common case.
539
- invariant(
540
- typeof element.type !== 'string',
541
- 'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
542
- 'components, not primitives (%s). Instead of calling `.render(el)` and ' +
543
- 'inspecting the rendered output, look at `el.props` directly instead.',
544
- element.type,
545
- );
546
- invariant(
547
- isForwardRef(element) ||
548
- typeof element.type === 'function' ||
549
- isMemo(element),
550
- 'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
551
- 'components, but the provided element type was `%s`.',
552
- Array.isArray(element.type)
553
- ? 'array'
554
- : element.type === null
555
- ? 'null'
556
- : typeof element.type,
557
- );
558
-
559
- if (this._rendering) {
560
- return;
561
- }
562
- if (this._element != null && this._element.type !== element.type) {
563
- this._reset();
564
- }
565
-
566
- const elementType = isMemo(element) ? element.type.type : element.type;
567
- const previousElement = this._element;
568
-
569
- this._rendering = true;
570
- this._element = element;
571
- this._context = getMaskedContext(elementType.contextTypes, context);
572
-
573
- // Inner memo component props aren't currently validated in createElement.
574
- if (isMemo(element) && elementType.propTypes) {
575
- currentlyValidatingElement = element;
576
- checkPropTypes(
577
- elementType.propTypes,
578
- element.props,
579
- 'prop',
580
- getComponentName(elementType),
581
- getStackAddendum,
582
- );
583
- }
584
-
585
- if (this._instance) {
586
- this._updateClassComponent(elementType, element, this._context);
587
- } else {
588
- if (shouldConstruct(elementType)) {
589
- this._instance = new elementType(
590
- element.props,
591
- this._context,
592
- this._updater,
593
- );
594
- if (typeof elementType.getDerivedStateFromProps === 'function') {
595
- const partialState = elementType.getDerivedStateFromProps.call(
596
- null,
597
- element.props,
598
- this._instance.state,
599
- );
600
- if (partialState != null) {
601
- this._instance.state = Object.assign(
602
- {},
603
- this._instance.state,
604
- partialState,
605
- );
606
- }
607
- }
608
-
609
- if (elementType.contextTypes) {
610
- currentlyValidatingElement = element;
611
- checkPropTypes(
612
- elementType.contextTypes,
613
- this._context,
614
- 'context',
615
- getName(elementType, this._instance),
616
- getStackAddendum,
617
- );
618
-
619
- currentlyValidatingElement = null;
620
- }
621
-
622
- this._mountClassComponent(elementType, element, this._context);
623
- } else {
624
- let shouldRender = true;
625
- if (isMemo(element) && previousElement !== null) {
626
- // This is a Memo component that is being re-rendered.
627
- const compare = element.type.compare || shallowEqual;
628
- if (compare(previousElement.props, element.props)) {
629
- shouldRender = false;
630
- }
631
- }
632
- if (shouldRender) {
633
- const prevDispatcher = ReactCurrentDispatcher.current;
634
- ReactCurrentDispatcher.current = this._dispatcher;
635
- try {
636
- // elementType could still be a ForwardRef if it was
637
- // nested inside Memo.
638
- if (elementType.$$typeof === ForwardRef) {
639
- invariant(
640
- typeof elementType.render === 'function',
641
- 'forwardRef requires a render function but was given %s.',
642
- typeof elementType.render,
643
- );
644
- this._rendered = elementType.render.call(
645
- undefined,
646
- element.props,
647
- element.ref,
648
- );
649
- } else {
650
- this._rendered = elementType(element.props, this._context);
651
- }
652
- } finally {
653
- ReactCurrentDispatcher.current = prevDispatcher;
654
- }
655
- this._finishHooks(element, context);
656
- }
657
- }
658
- }
659
-
660
- this._rendering = false;
661
- this._updater._invokeCallbacks();
662
-
663
- return this.getRenderOutput();
664
- }
665
-
666
- unmount() {
667
- if (this._instance) {
668
- if (typeof this._instance.componentWillUnmount === 'function') {
669
- this._instance.componentWillUnmount();
670
- }
671
- }
672
- this._reset();
673
- }
674
-
675
- _mountClassComponent(
676
- elementType: Function,
677
- element: ReactElement,
678
- context: null | Object,
679
- ) {
680
- this._instance.context = context;
681
- this._instance.props = element.props;
682
- this._instance.state = this._instance.state || null;
683
- this._instance.updater = this._updater;
684
-
685
- if (
686
- typeof this._instance.UNSAFE_componentWillMount === 'function' ||
687
- typeof this._instance.componentWillMount === 'function'
688
- ) {
689
- const beforeState = this._newState;
690
-
691
- // In order to support react-lifecycles-compat polyfilled components,
692
- // Unsafe lifecycles should not be invoked for components using the new APIs.
693
- if (
694
- typeof elementType.getDerivedStateFromProps !== 'function' &&
695
- typeof this._instance.getSnapshotBeforeUpdate !== 'function'
696
- ) {
697
- if (typeof this._instance.componentWillMount === 'function') {
698
- this._instance.componentWillMount();
699
- }
700
- if (typeof this._instance.UNSAFE_componentWillMount === 'function') {
701
- this._instance.UNSAFE_componentWillMount();
702
- }
703
- }
704
-
705
- // setState may have been called during cWM
706
- if (beforeState !== this._newState) {
707
- this._instance.state = this._newState || emptyObject;
708
- }
709
- }
710
-
711
- this._rendered = this._instance.render();
712
- // Intentionally do not call componentDidMount()
713
- // because DOM refs are not available.
714
- }
715
-
716
- _updateClassComponent(
717
- elementType: Function,
718
- element: ReactElement,
719
- context: null | Object,
720
- ) {
721
- const {props} = element;
722
-
723
- const oldState = this._instance.state || emptyObject;
724
- const oldProps = this._instance.props;
725
-
726
- if (oldProps !== props) {
727
- // In order to support react-lifecycles-compat polyfilled components,
728
- // Unsafe lifecycles should not be invoked for components using the new APIs.
729
- if (
730
- typeof elementType.getDerivedStateFromProps !== 'function' &&
731
- typeof this._instance.getSnapshotBeforeUpdate !== 'function'
732
- ) {
733
- if (typeof this._instance.componentWillReceiveProps === 'function') {
734
- this._instance.componentWillReceiveProps(props, context);
735
- }
736
- if (
737
- typeof this._instance.UNSAFE_componentWillReceiveProps === 'function'
738
- ) {
739
- this._instance.UNSAFE_componentWillReceiveProps(props, context);
740
- }
741
- }
742
- }
743
-
744
- // Read state after cWRP in case it calls setState
745
- let state = this._newState || oldState;
746
- if (typeof elementType.getDerivedStateFromProps === 'function') {
747
- const partialState = elementType.getDerivedStateFromProps.call(
748
- null,
749
- props,
750
- state,
751
- );
752
- if (partialState != null) {
753
- state = Object.assign({}, state, partialState);
754
- }
755
- }
756
-
757
- let shouldUpdate = true;
758
- if (this._forcedUpdate) {
759
- shouldUpdate = true;
760
- this._forcedUpdate = false;
761
- } else if (typeof this._instance.shouldComponentUpdate === 'function') {
762
- shouldUpdate = !!this._instance.shouldComponentUpdate(
763
- props,
764
- state,
765
- context,
766
- );
767
- } else if (
768
- elementType.prototype &&
769
- elementType.prototype.isPureReactComponent
770
- ) {
771
- shouldUpdate =
772
- !shallowEqual(oldProps, props) || !shallowEqual(oldState, state);
773
- }
774
-
775
- if (shouldUpdate) {
776
- // In order to support react-lifecycles-compat polyfilled components,
777
- // Unsafe lifecycles should not be invoked for components using the new APIs.
778
- if (
779
- typeof elementType.getDerivedStateFromProps !== 'function' &&
780
- typeof this._instance.getSnapshotBeforeUpdate !== 'function'
781
- ) {
782
- if (typeof this._instance.componentWillUpdate === 'function') {
783
- this._instance.componentWillUpdate(props, state, context);
784
- }
785
- if (typeof this._instance.UNSAFE_componentWillUpdate === 'function') {
786
- this._instance.UNSAFE_componentWillUpdate(props, state, context);
787
- }
788
- }
789
- }
790
-
791
- this._instance.context = context;
792
- this._instance.props = props;
793
- this._instance.state = state;
794
- this._newState = null;
795
-
796
- if (shouldUpdate) {
797
- this._rendered = this._instance.render();
798
- }
799
- // Intentionally do not call componentDidUpdate()
800
- // because DOM refs are not available.
801
- }
802
-}
803
-
804
-let currentlyValidatingElement = null;
805
-
806
-function getDisplayName(element) {
807
- if (element == null) {
808
- return '#empty';
809
- } else if (typeof element === 'string' || typeof element === 'number') {
810
- return '#text';
811
- } else if (typeof element.type === 'string') {
812
- return element.type;
813
- } else {
814
- const elementType = isMemo(element) ? element.type.type : element.type;
815
- return elementType.displayName || elementType.name || 'Unknown';
816
- }
817
-}
818
-
819
-function getStackAddendum() {
820
- let stack = '';
821
- if (currentlyValidatingElement) {
822
- const name = getDisplayName(currentlyValidatingElement);
823
- const owner = currentlyValidatingElement._owner;
824
- stack += describeComponentFrame(
825
- name,
826
- currentlyValidatingElement._source,
827
- owner && getComponentName(owner.type),
828
- );
829
- }
830
- return stack;
831
-}
832
-
833
-function getName(type, instance) {
834
- const constructor = instance && instance.constructor;
835
- return (
836
- type.displayName ||
837
- (constructor && constructor.displayName) ||
838
- type.name ||
839
- (constructor && constructor.name) ||
840
- null
841
- );
842
-}
843
-
844
-function shouldConstruct(Component) {
845
- return !!(Component.prototype && Component.prototype.isReactComponent);
846
-}
847
-
848
-function getMaskedContext(contextTypes, unmaskedContext) {
849
- if (!contextTypes || !unmaskedContext) {
850
- return emptyObject;
851
- }
852
- const context = {};
853
- for (let key in contextTypes) {
854
- context[key] = unmaskedContext[key];
855
- }
856
- return context;
857
-}
858
-
859
-// This should probably be a default export and a named export.
860
-// However, this not how any of other APIs are designed so doesn't line up
861
-// with our build configs and makes it hard to properly support ES modules
862
-// and CommonJS.
863
-export default ReactShallowRenderer;
yarn.lock
+9
@@ -10856,6 +10856,15 @@ react-native-web@^0.11.5:
10856
prop-types "^15.6.0"
10857
react-timer-mixin "^0.13.4"
10858
10859
+react-shallow-renderer@^16.12.0:
10860
+ version "16.12.0"
10861
+ resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.12.0.tgz#e68ca8fca7a616db42c36fdd6929723ba0bccef6"
10862
+ integrity sha512-elIe2dhXJAO19IY1K3b4YWHBLnKE5wRH+PKx3AYzM6j2+N5UI+FGLKiRNFbLQcggrpBiy3GLhj7MqNUlRk9Z7g==
10863
+ dependencies:
10864
+ object-assign "^4.1.1"
10865
+ prop-types "^15.7.2"
10866
+ react-is "^16.12.0"
10867
+
10868
react-timer-mixin@^0.13.4:
10869
version "0.13.4"
10870
resolved "https://registry.yarnpkg.com/react-timer-mixin/-/react-timer-mixin-0.13.4.tgz#75a00c3c94c13abe29b43d63b4c65a88fc8264d3"