@samitouri / QOS-React-2 / commits / d17b9a13f8

Confirm that a shallow bailout does not drop work in the child

Includes a test that confirms that work that is bailed out before completing can be reused without dropping the entire subtree.

Andrew Clark committed Jan 7, 2017 at 17:26 UTC d17b9a13f8519c349c80c3ef2e95361e15f6bdf0
3 files changed +80 -1
scripts/fiber/tests-passing.txt
+1
@@ -1143,6 +1143,7 @@ src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
1143 * can resume work in a subtree even when a parent bails out
1144 * can resume work in a bailed subtree within one pass
1145 * can reuse work done after being preempted
1146 +* can reuse work that began but did not complete, after being preempted
1147 * can reuse work if shouldComponentUpdate is false, after being preempted
1148 * memoizes work even if shouldComponentUpdate returns false
1149 * can update in the middle of a tree using setState
src/renderers/shared/fiber/ReactFiberCompleteWork.js
-1
@@ -266,7 +266,6 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
266 const textInstance = createTextInstance(newText, rootContainerInstance, currentHostContext, workInProgress);
267 workInProgress.stateNode = textInstance;
268 }
269 - workInProgress.memoizedProps = newText;
269 return null;
270 case CoroutineComponent:
271 return moveCoroutineToHandlerPhase(current, workInProgress);
src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
+79
@@ -541,6 +541,85 @@ describe('ReactIncremental', () => {
541
542 });
543
544 + it('can reuse work that began but did not complete, after being preempted', () => {
545 + let ops = [];
546 + let child;
547 + let sibling;
548 +
549 + function GreatGrandchild() {
550 + ops.push('GreatGrandchild');
551 + return <div />;
552 + }
553 +
554 + function Grandchild() {
555 + ops.push('Grandchild');
556 + return <GreatGrandchild />;
557 + }
558 +
559 + class Child extends React.Component {
560 + state = { step: 0 };
561 + render() {
562 + child = this;
563 + ops.push('Child');
564 + return <Grandchild />;
565 + }
566 + }
567 +
568 + class Sibling extends React.Component {
569 + render() {
570 + ops.push('Sibling');
571 + sibling = this;
572 + return <div />;
573 + }
574 + }
575 +
576 + function Parent() {
577 + ops.push('Parent');
578 + return [
579 + // The extra div is necessary because when Parent bails out during the
580 + // high priority update, its progressedPriority is set to high.
581 + // So its direct children cannot be reused when we resume at
582 + // low priority. I think this would be fixed by changing
583 + // pendingWorkPriority and progressedPriority to be the priority of
584 + // the children only, not including the fiber itself.
585 + <div><Child /></div>,
586 + <Sibling />,
587 + ];
588 + }
589 +
590 + ReactNoop.render(<Parent />);
591 + ReactNoop.flush();
592 + ops = [];
593 +
594 + // Begin working on a low priority update to Child, but stop before
595 + // GreatGrandchild. Child and Grandchild begin but don't complete.
596 + child.setState({ step: 1 });
597 + ReactNoop.flushDeferredPri(30);
598 + expect(ops).toEqual([
599 + 'Child',
600 + 'Grandchild',
601 + ]);
602 +
603 + // Interrupt the current low pri work with a high pri update elsewhere in
604 + // the tree.
605 + ops = [];
606 + ReactNoop.performAnimationWork(() => {
607 + sibling.setState({});
608 + });
609 + ReactNoop.flushAnimationPri();
610 + expect(ops).toEqual(['Sibling']);
611 +
612 + // Continue the low pri work. The work on Child and GrandChild was memoized
613 + // so they should not be worked on again.
614 + ops = [];
615 + ReactNoop.flush();
616 + expect(ops).toEqual([
617 + // No Child
618 + // No Grandchild
619 + 'GreatGrandchild',
620 + ]);
621 + });
622 +
623 it('can reuse work if shouldComponentUpdate is false, after being preempted', () => {
624
625 var ops = [];