@@ -365,6 +365,36 @@ module.exports = function(
365365 }
366366 }
367367
368+ function callComponentWillReceiveProps (
369+ workInProgress ,
370+ instance ,
371+ newProps ,
372+ newContext ,
373+ ) {
374+ if ( typeof instance . componentWillReceiveProps === 'function' ) {
375+ if ( __DEV__ ) {
376+ startPhaseTimer ( workInProgress , 'componentWillReceiveProps' ) ;
377+ }
378+ instance . componentWillReceiveProps ( newProps , newContext ) ;
379+ if ( __DEV__ ) {
380+ stopPhaseTimer ( ) ;
381+ }
382+
383+ if ( instance . state !== workInProgress . memoizedState ) {
384+ if ( __DEV__ ) {
385+ warning (
386+ false ,
387+ '%s.componentWillReceiveProps(): Assigning directly to ' +
388+ "this.state is deprecated (except inside a component's " +
389+ 'constructor). Use setState instead.' ,
390+ getComponentName ( workInProgress ) ,
391+ ) ;
392+ }
393+ updater . enqueueReplaceState ( instance , instance . state , null ) ;
394+ }
395+ }
396+ }
397+
368398 // Called on a preexisting class instance. Returns false if a resumed render
369399 // could be reused.
370400 function resumeMountClassInstance (
@@ -389,6 +419,17 @@ module.exports = function(
389419 const newUnmaskedContext = getUnmaskedContext ( workInProgress ) ;
390420 const newContext = getMaskedContext ( workInProgress , newUnmaskedContext ) ;
391421
422+ const oldContext = instance . context ;
423+ const oldProps = workInProgress . memoizedProps ;
424+ if ( oldProps !== newProps || oldContext !== newContext ) {
425+ callComponentWillReceiveProps (
426+ workInProgress ,
427+ instance ,
428+ newProps ,
429+ newContext ,
430+ ) ;
431+ }
432+
392433 // TODO: Should we deal with a setState that happened after the last
393434 // componentWillMount and before this componentWillMount? Probably
394435 // unsupported anyway.
@@ -411,31 +452,42 @@ module.exports = function(
411452 return false ;
412453 }
413454
414- // If we didn't bail out we need to construct a new instance. We don't
415- // want to reuse one that failed to fully mount.
416- const newInstance = constructClassInstance ( workInProgress , newProps ) ;
417- newInstance . props = newProps ;
418- newInstance . state = newState = newInstance . state || null ;
419- newInstance . context = newContext ;
455+ // componentWillMount may have called setState. Process the update queue.
456+ let newUpdateQueue = workInProgress . updateQueue ;
457+ if ( newUpdateQueue !== null ) {
458+ newState = beginUpdateQueue (
459+ workInProgress ,
460+ newUpdateQueue ,
461+ instance ,
462+ newState ,
463+ newProps ,
464+ priorityLevel ,
465+ ) ;
466+ }
420467
421- if ( typeof newInstance . componentWillMount === 'function' ) {
468+ // Update the input pointers now so that they are correct when we call
469+ // componentWillMount
470+ instance . props = newProps ;
471+ instance . state = newState ;
472+ instance . context = newContext ;
473+
474+ if ( typeof instance . componentWillMount === 'function' ) {
422475 if ( __DEV__ ) {
423476 startPhaseTimer ( workInProgress , 'componentWillMount' ) ;
424477 }
425- newInstance . componentWillMount ( ) ;
478+ instance . componentWillMount ( ) ;
426479 if ( __DEV__ ) {
427480 stopPhaseTimer ( ) ;
428481 }
429482 }
430- // If we had additional state updates, process them now.
431- // They may be from componentWillMount() or from error boundary's setState()
432- // during initial mounting.
433- const newUpdateQueue = workInProgress . updateQueue ;
483+
484+ // componentWillMount may have called setState. Process the update queue.
485+ newUpdateQueue = workInProgress . updateQueue ;
434486 if ( newUpdateQueue !== null ) {
435- newInstance . state = beginUpdateQueue (
487+ newState = beginUpdateQueue (
436488 workInProgress ,
437489 newUpdateQueue ,
438- newInstance ,
490+ instance ,
439491 newState ,
440492 newProps ,
441493 priorityLevel ,
@@ -444,6 +496,9 @@ module.exports = function(
444496 if ( typeof instance . componentDidMount === 'function' ) {
445497 workInProgress . effectTag |= Update ;
446498 }
499+
500+ instance . state = newState ;
501+
447502 return true ;
448503 }
449504
@@ -477,28 +532,12 @@ module.exports = function(
477532 // during componentDidUpdate we pass the "current" props.
478533
479534 if ( oldProps !== newProps || oldContext !== newContext ) {
480- if ( typeof instance . componentWillReceiveProps === 'function' ) {
481- if ( __DEV__ ) {
482- startPhaseTimer ( workInProgress , 'componentWillReceiveProps' ) ;
483- }
484- instance . componentWillReceiveProps ( newProps , newContext ) ;
485- if ( __DEV__ ) {
486- stopPhaseTimer ( ) ;
487- }
488-
489- if ( instance . state !== workInProgress . memoizedState ) {
490- if ( __DEV__ ) {
491- warning (
492- false ,
493- '%s.componentWillReceiveProps(): Assigning directly to ' +
494- "this.state is deprecated (except inside a component's " +
495- 'constructor). Use setState instead.' ,
496- getComponentName ( workInProgress ) ,
497- ) ;
498- }
499- updater . enqueueReplaceState ( instance , instance . state , null ) ;
500- }
501- }
535+ callComponentWillReceiveProps (
536+ workInProgress ,
537+ instance ,
538+ newProps ,
539+ newContext ,
540+ ) ;
502541 }
503542
504543 // Compute the next state using the memoized state and the update queue.
0 commit comments