Skip to content

Commit

Permalink
Confirm that a shallow bailout does not drop work in the child
Browse files Browse the repository at this point in the history
Includes a test that confirms that work that is bailed out before
completing can be reused without dropping the entire subtree.
  • Loading branch information
acdlite committed Jan 12, 2017
1 parent 1ed304f commit d17b9a1
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 1 deletion.
1 change: 1 addition & 0 deletions scripts/fiber/tests-passing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,7 @@ src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
* can resume work in a subtree even when a parent bails out
* can resume work in a bailed subtree within one pass
* can reuse work done after being preempted
* can reuse work that began but did not complete, after being preempted
* can reuse work if shouldComponentUpdate is false, after being preempted
* memoizes work even if shouldComponentUpdate returns false
* can update in the middle of a tree using setState
Expand Down
1 change: 0 additions & 1 deletion src/renderers/shared/fiber/ReactFiberCompleteWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@ module.exports = function<T, P, I, TI, PI, C, CX>(
const textInstance = createTextInstance(newText, rootContainerInstance, currentHostContext, workInProgress);
workInProgress.stateNode = textInstance;
}
workInProgress.memoizedProps = newText;
return null;
case CoroutineComponent:
return moveCoroutineToHandlerPhase(current, workInProgress);
Expand Down
79 changes: 79 additions & 0 deletions src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,85 @@ describe('ReactIncremental', () => {

});

it('can reuse work that began but did not complete, after being preempted', () => {
let ops = [];
let child;
let sibling;

function GreatGrandchild() {
ops.push('GreatGrandchild');
return <div />;
}

function Grandchild() {
ops.push('Grandchild');
return <GreatGrandchild />;
}

class Child extends React.Component {
state = { step: 0 };
render() {
child = this;
ops.push('Child');
return <Grandchild />;
}
}

class Sibling extends React.Component {
render() {
ops.push('Sibling');
sibling = this;
return <div />;
}
}

function Parent() {
ops.push('Parent');
return [
// The extra div is necessary because when Parent bails out during the
// high priority update, its progressedPriority is set to high.
// So its direct children cannot be reused when we resume at
// low priority. I think this would be fixed by changing
// pendingWorkPriority and progressedPriority to be the priority of
// the children only, not including the fiber itself.
<div><Child /></div>,
<Sibling />,
];
}

ReactNoop.render(<Parent />);
ReactNoop.flush();
ops = [];

// Begin working on a low priority update to Child, but stop before
// GreatGrandchild. Child and Grandchild begin but don't complete.
child.setState({ step: 1 });
ReactNoop.flushDeferredPri(30);
expect(ops).toEqual([
'Child',
'Grandchild',
]);

// Interrupt the current low pri work with a high pri update elsewhere in
// the tree.
ops = [];
ReactNoop.performAnimationWork(() => {
sibling.setState({});
});
ReactNoop.flushAnimationPri();
expect(ops).toEqual(['Sibling']);

// Continue the low pri work. The work on Child and GrandChild was memoized
// so they should not be worked on again.
ops = [];
ReactNoop.flush();
expect(ops).toEqual([
// No Child
// No Grandchild
'GreatGrandchild',
]);
});

it('can reuse work if shouldComponentUpdate is false, after being preempted', () => {

var ops = [];
Expand Down

0 comments on commit d17b9a1

Please sign in to comment.