@@ -40,12 +40,23 @@ import {hasContextChanged} from './ReactFiberContext';
40
40
const fakeInternalInstance = { } ;
41
41
const isArray = Array . isArray ;
42
42
43
+ let didWarnAboutLegacyWillMount ;
44
+ let didWarnAboutLegacyWillReceiveProps ;
45
+ let didWarnAboutLegacyWillUpdate ;
43
46
let didWarnAboutStateAssignmentForComponent ;
47
+ let didWarnAboutUndefinedDerivedState ;
48
+ let didWarnAboutWillReceivePropsAndDerivedState ;
44
49
let warnOnInvalidCallback ;
45
50
46
51
if ( __DEV__ ) {
47
- const didWarnOnInvalidCallback = { } ;
52
+ didWarnAboutLegacyWillMount = { } ;
53
+ didWarnAboutLegacyWillReceiveProps = { } ;
54
+ didWarnAboutLegacyWillUpdate = { } ;
48
55
didWarnAboutStateAssignmentForComponent = { } ;
56
+ didWarnAboutUndefinedDerivedState = { } ;
57
+ didWarnAboutWillReceivePropsAndDerivedState = { } ;
58
+
59
+ const didWarnOnInvalidCallback = { } ;
49
60
50
61
warnOnInvalidCallback = function ( callback : mixed , callerName : string ) {
51
62
if ( callback === null || typeof callback === 'function' ) {
@@ -380,8 +391,17 @@ export default function(
380
391
const instance = new ctor ( props , context ) ;
381
392
adoptClassInstance ( workInProgress , instance ) ;
382
393
383
- // TODO (getDerivedStateFromProps) Call Component.getDerivedStateFromProps
384
- // Merge the returned value into instance.state
394
+ const partialState = callGetDerivedStateFromProps (
395
+ workInProgress ,
396
+ instance ,
397
+ props ,
398
+ ) ;
399
+ if ( partialState ) {
400
+ // Render-phase updates (like this) should not be added to the update queue,
401
+ // So that multiple render passes do not enqueue multiple updates.
402
+ // Instead, just synchronously merge the returned state into the instance.
403
+ instance . state = Object . assign ( { } , instance . state , partialState ) ;
404
+ }
385
405
386
406
// Cache unmasked context so we can avoid recreating masked context unless necessary.
387
407
// ReactFiberContext usually updates this cache but can't for newly-created instances.
@@ -398,12 +418,16 @@ export default function(
398
418
399
419
if ( typeof instance . componentWillMount === 'function' ) {
400
420
if ( __DEV__ ) {
401
- warning (
402
- false ,
403
- '%s: componentWillMount() is deprecated and will be removed in the ' +
404
- 'next major version. Please use UNSAFE_componentWillMount() instead.' ,
405
- getComponentName ( workInProgress ) ,
406
- ) ;
421
+ const componentName = getComponentName ( workInProgress ) || 'Unknown' ;
422
+ if ( ! didWarnAboutLegacyWillMount [ componentName ] ) {
423
+ warning (
424
+ false ,
425
+ '%s: componentWillMount() is deprecated and will be removed in the ' +
426
+ 'next major version. Please use UNSAFE_componentWillMount() instead.' ,
427
+ componentName ,
428
+ ) ;
429
+ didWarnAboutLegacyWillMount [ componentName ] = true ;
430
+ }
407
431
}
408
432
instance . componentWillMount ( ) ;
409
433
} else {
@@ -435,12 +459,16 @@ export default function(
435
459
const oldState = instance . state ;
436
460
if ( typeof instance . componentWillReceiveProps === 'function' ) {
437
461
if ( __DEV__ ) {
438
- warning (
439
- false ,
440
- '%s: componentWillReceiveProps() is deprecated and will be removed in the ' +
441
- 'next major version. Please use UNSAFE_componentWillReceiveProps() instead.' ,
442
- getComponentName ( workInProgress ) ,
443
- ) ;
462
+ const componentName = getComponentName ( workInProgress ) || 'Unknown' ;
463
+ if ( ! didWarnAboutLegacyWillReceiveProps [ componentName ] ) {
464
+ warning (
465
+ false ,
466
+ '%s: componentWillReceiveProps() is deprecated and will be removed in the ' +
467
+ 'next major version. Please use UNSAFE_componentWillReceiveProps() instead.' ,
468
+ componentName ,
469
+ ) ;
470
+ didWarnAboutLegacyWillReceiveProps [ componentName ] = true ;
471
+ }
444
472
}
445
473
446
474
startPhaseTimer ( workInProgress , 'componentWillReceiveProps' ) ;
@@ -457,18 +485,9 @@ export default function(
457
485
}
458
486
}
459
487
460
- // TODO (getDerivedStateFromProps) If both cWRP and static gDSFP methods exist, warn.
461
- // Call cWRP first then static gDSFP; don't bother trying to sync apply setState() changes.
462
-
463
- // TODO (getDerivedStateFromProps) Call Component.getDerivedStateFromProps
464
-
465
- // TODO (getDerivedStateFromProps) Returned value should not be added to update queue.
466
- // Just synchronously Object.assign it into instance.state
467
- // This should be covered in a test too.
468
-
469
488
if ( instance . state !== oldState ) {
470
489
if ( __DEV__ ) {
471
- const componentName = getComponentName ( workInProgress ) || 'Component ' ;
490
+ const componentName = getComponentName ( workInProgress ) || 'Unknown ' ;
472
491
if ( ! didWarnAboutStateAssignmentForComponent [ componentName ] ) {
473
492
warning (
474
493
false ,
@@ -484,6 +503,50 @@ export default function(
484
503
}
485
504
}
486
505
506
+ function callGetDerivedStateFromProps ( workInProgress , instance , props ) {
507
+ const { type} = workInProgress ;
508
+
509
+ if ( typeof type . getDerivedStateFromProps === 'function' ) {
510
+ if ( __DEV__ ) {
511
+ if (
512
+ typeof instance . componentWillReceiveProps === 'function' ||
513
+ typeof instance . UNSAFE_componentWillReceiveProps === 'function'
514
+ ) {
515
+ const componentName = getComponentName ( workInProgress ) || 'Unknown' ;
516
+ if ( ! didWarnAboutWillReceivePropsAndDerivedState [ componentName ] ) {
517
+ warning (
518
+ false ,
519
+ '%s: Defines both componentWillReceiveProps() and static ' +
520
+ 'getDerivedStateFromProps() methods. We recommend using ' +
521
+ 'only getDerivedStateFromProps().' ,
522
+ componentName ,
523
+ ) ;
524
+ didWarnAboutWillReceivePropsAndDerivedState [ componentName ] = true ;
525
+ }
526
+ }
527
+ }
528
+
529
+ const partialState = type . getDerivedStateFromProps ( props , instance . state ) ;
530
+
531
+ if ( __DEV__ ) {
532
+ if ( partialState === undefined ) {
533
+ const componentName = getComponentName ( workInProgress ) || 'Unknown' ;
534
+ if ( ! didWarnAboutUndefinedDerivedState [ componentName ] ) {
535
+ warning (
536
+ false ,
537
+ '%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. ' +
538
+ 'You may have returned undefined.' ,
539
+ componentName ,
540
+ ) ;
541
+ didWarnAboutUndefinedDerivedState [ componentName ] = componentName ;
542
+ }
543
+ }
544
+ }
545
+
546
+ return partialState || null ;
547
+ }
548
+ }
549
+
487
550
// Invokes the mount life-cycles on a previously never rendered instance.
488
551
function mountClassInstance (
489
552
workInProgress : Fiber ,
@@ -675,6 +738,12 @@ export default function(
675
738
) ;
676
739
}
677
740
741
+ const partialState = callGetDerivedStateFromProps (
742
+ workInProgress ,
743
+ instance ,
744
+ newProps ,
745
+ ) ;
746
+
678
747
// Compute the next state using the memoized state and the update queue.
679
748
const oldState = workInProgress . memoizedState ;
680
749
// TODO: Previous state can be null.
@@ -692,6 +761,13 @@ export default function(
692
761
newState = oldState ;
693
762
}
694
763
764
+ if ( partialState ) {
765
+ // Render-phase updates (like this) should not be added to the update queue,
766
+ // So that multiple render passes do not enqueue multiple updates.
767
+ // Instead, just synchronously merge the returned state into the instance.
768
+ newState = Object . assign ( { } , newState , partialState ) ;
769
+ }
770
+
695
771
if (
696
772
oldProps === newProps &&
697
773
oldState === newState &&
@@ -730,12 +806,17 @@ export default function(
730
806
) {
731
807
if ( typeof instance . componentWillUpdate === 'function' ) {
732
808
if ( __DEV__ ) {
733
- warning (
734
- false ,
735
- '%s: componentWillUpdate() is deprecated and will be removed in the ' +
736
- 'next major version. Please use UNSAFE_componentWillUpdate() instead.' ,
737
- getComponentName ( workInProgress ) ,
738
- ) ;
809
+ const componentName =
810
+ getComponentName ( workInProgress ) || 'Component' ;
811
+ if ( ! didWarnAboutLegacyWillUpdate [ componentName ] ) {
812
+ warning (
813
+ false ,
814
+ '%s: componentWillUpdate() is deprecated and will be removed in the ' +
815
+ 'next major version. Please use UNSAFE_componentWillUpdate() instead.' ,
816
+ componentName ,
817
+ ) ;
818
+ didWarnAboutLegacyWillUpdate [ componentName ] = true ;
819
+ }
739
820
}
740
821
741
822
startPhaseTimer ( workInProgress , 'componentWillUpdate' ) ;
0 commit comments