@@ -380,7 +380,7 @@ describe('ReactIncrementalSideEffects', () => {
380380 it ( 'can defer side-effects and resume them later on' , function ( ) {
381381 class Bar extends React . Component {
382382 shouldComponentUpdate ( nextProps ) {
383- return this . props . idx !== nextProps ;
383+ return this . props . idx !== nextProps . idx ;
384384 }
385385 render ( ) {
386386 return < span prop = { this . props . idx } /> ;
@@ -437,10 +437,11 @@ describe('ReactIncrementalSideEffects', () => {
437437 )
438438 ) ,
439439 ] ) ;
440- ReactNoop . flushDeferredPri ( 30 ) ;
440+ ReactNoop . render ( < Foo tick = { 3 } idx = { 1 } /> ) ;
441+ ReactNoop . flush ( ) ;
441442 expect ( ReactNoop . root . children ) . toEqual ( [
442443 div (
443- span ( 2 ) ,
444+ span ( 3 ) ,
444445 div (
445446 // New numbers.
446447 span ( 1 ) ,
@@ -456,6 +457,149 @@ describe('ReactIncrementalSideEffects', () => {
456457 expect ( innerSpanA ) . toBe ( innerSpanB ) ;
457458 } ) ;
458459
460+ it ( 'can defer side-effects and reuse them later - complex' , function ( ) {
461+ var ops = [ ] ;
462+
463+ class Bar extends React . Component {
464+ shouldComponentUpdate ( nextProps ) {
465+ return this . props . idx !== nextProps . idx ;
466+ }
467+ render ( ) {
468+ ops . push ( 'Bar' ) ;
469+ return < span prop = { this . props . idx } /> ;
470+ }
471+ }
472+ class Baz extends React . Component {
473+ shouldComponentUpdate ( nextProps ) {
474+ return this . props . idx !== nextProps . idx ;
475+ }
476+ render ( ) {
477+ ops . push ( 'Baz' ) ;
478+ return [ < Bar idx = { this . props . idx } /> , < Bar idx = { this . props . idx } /> ] ;
479+ }
480+ }
481+ function Foo ( props ) {
482+ ops . push ( 'Foo' ) ;
483+ return (
484+ < div >
485+ < span prop = { props . tick } />
486+ < div hidden = { true } >
487+ < Baz idx = { props . idx } />
488+ < Baz idx = { props . idx } />
489+ < Baz idx = { props . idx } />
490+ </ div >
491+ </ div >
492+ ) ;
493+ }
494+ ReactNoop . render ( < Foo tick = { 0 } idx = { 0 } /> ) ;
495+ ReactNoop . flushDeferredPri ( 65 ) ;
496+ expect ( ReactNoop . root . children ) . toEqual ( [
497+ div (
498+ span ( 0 ) ,
499+ div ( /*the spans are down-prioritized and not rendered yet*/ )
500+ ) ,
501+ ] ) ;
502+
503+ expect ( ops ) . toEqual ( [ 'Foo' , 'Baz' , 'Bar' ] ) ;
504+ ops = [ ] ;
505+
506+ ReactNoop . render ( < Foo tick = { 1 } idx = { 0 } /> ) ;
507+ ReactNoop . flushDeferredPri ( 70 ) ;
508+ expect ( ReactNoop . root . children ) . toEqual ( [
509+ div (
510+ span ( 1 ) ,
511+ div ( /*still not rendered yet*/ )
512+ ) ,
513+ ] ) ;
514+
515+ expect ( ops ) . toEqual ( [ 'Foo' , 'Baz' , 'Bar' ] ) ;
516+ ops = [ ] ;
517+
518+ ReactNoop . flush ( ) ;
519+ expect ( ReactNoop . root . children ) . toEqual ( [
520+ div (
521+ span ( 1 ) ,
522+ div (
523+ // Now we had enough time to finish the spans.
524+ span ( 0 ) ,
525+ span ( 0 ) ,
526+ span ( 0 ) ,
527+ span ( 0 ) ,
528+ span ( 0 ) ,
529+ span ( 0 )
530+ )
531+ ) ,
532+ ] ) ;
533+
534+ expect ( ops ) . toEqual ( [ 'Bar' , 'Baz' , 'Bar' , 'Bar' , 'Baz' , 'Bar' , 'Bar' ] ) ;
535+ ops = [ ] ;
536+
537+ // Now we're going to update the index but we'll only let it finish half
538+ // way through.
539+ ReactNoop . render ( < Foo tick = { 2 } idx = { 1 } /> ) ;
540+ ReactNoop . flushDeferredPri ( 95 ) ;
541+ expect ( ReactNoop . root . children ) . toEqual ( [
542+ div (
543+ span ( 2 ) ,
544+ div (
545+ // Still same old numbers.
546+ span ( 0 ) ,
547+ span ( 0 ) ,
548+ span ( 0 ) ,
549+ span ( 0 ) ,
550+ span ( 0 ) ,
551+ span ( 0 )
552+ )
553+ ) ,
554+ ] ) ;
555+
556+ // We let it finish half way through. That means we'll have one fully
557+ // completed Baz, one half-way completed Baz and one fully incomplete Baz.
558+ expect ( ops ) . toEqual ( [ 'Foo' , 'Baz' , 'Bar' , 'Bar' , 'Baz' , 'Bar' ] ) ;
559+ ops = [ ] ;
560+
561+ // We'll update again, without letting the new index update yet. Only half
562+ // way through.
563+ ReactNoop . render ( < Foo tick = { 3 } idx = { 1 } /> ) ;
564+ ReactNoop . flushDeferredPri ( 50 ) ;
565+ expect ( ReactNoop . root . children ) . toEqual ( [
566+ div (
567+ span ( 3 ) ,
568+ div (
569+ // Old numbers.
570+ span ( 0 ) ,
571+ span ( 0 ) ,
572+ span ( 0 ) ,
573+ span ( 0 ) ,
574+ span ( 0 ) ,
575+ span ( 0 )
576+ )
577+ ) ,
578+ ] ) ;
579+
580+ expect ( ops ) . toEqual ( [ 'Foo' ] ) ;
581+ ops = [ ] ;
582+
583+ // We should now be able to reuse some of the work we've already done
584+ // and replay those side-effects.
585+ ReactNoop . flush ( ) ;
586+ expect ( ReactNoop . root . children ) . toEqual ( [
587+ div (
588+ span ( 3 ) ,
589+ div (
590+ // New numbers.
591+ span ( 1 ) ,
592+ span ( 1 ) ,
593+ span ( 1 ) ,
594+ span ( 1 ) ,
595+ span ( 1 ) ,
596+ span ( 1 )
597+ )
598+ ) ,
599+ ] ) ;
600+
601+ expect ( ops ) . toEqual ( [ 'Baz' , 'Bar' , 'Baz' , 'Bar' , 'Bar' ] ) ;
602+ } ) ;
459603
460604 // TODO: Test that side-effects are not cut off when a work in progress node
461605 // moves to "current" without flushing due to having lower priority. Does this
0 commit comments