diff --git a/packages/react-noop-renderer/src/ReactNoop.js b/packages/react-noop-renderer/src/ReactNoop.js index a25821006c5f..f7a895ff9bb1 100644 --- a/packages/react-noop-renderer/src/ReactNoop.js +++ b/packages/react-noop-renderer/src/ReactNoop.js @@ -455,7 +455,11 @@ var ReactNoop = { unbatchedUpdates: NoopRenderer.unbatchedUpdates, - flushSync: NoopRenderer.flushSync, + flushSync(fn: () => mixed) { + yieldedValues = []; + NoopRenderer.flushSync(fn); + return yieldedValues; + }, // Logs the current state of the tree. dumpTree(rootID: string = DEFAULT_ROOT_ID) { diff --git a/packages/react-reconciler/src/ReactFiberScheduler.js b/packages/react-reconciler/src/ReactFiberScheduler.js index 5d85c0ad179d..5f47c83c1ea8 100644 --- a/packages/react-reconciler/src/ReactFiberScheduler.js +++ b/packages/react-reconciler/src/ReactFiberScheduler.js @@ -1202,7 +1202,7 @@ export default function( if ( !isWorking && root === nextRoot && - expirationTime <= nextRenderExpirationTime + expirationTime < nextRenderExpirationTime ) { // Restart the root from the top. if (nextUnitOfWork !== null) { diff --git a/packages/react-reconciler/src/__tests__/ReactIncremental-test.js b/packages/react-reconciler/src/__tests__/ReactIncremental-test.js index 7979db6cece5..5bb476554336 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncremental-test.js +++ b/packages/react-reconciler/src/__tests__/ReactIncremental-test.js @@ -168,6 +168,7 @@ describe('ReactIncremental', () => { ops = []; // This will abort the previous work and restart + ReactNoop.flushSync(() => ReactNoop.render(null)); ReactNoop.render(); // Flush part of the new work @@ -221,6 +222,7 @@ describe('ReactIncremental', () => { expect(ops).toEqual(['setState1']); // This will abort the previous work and restart + ReactNoop.flushSync(() => ReactNoop.render()); inst.setState( () => { ops.push('setState2'); @@ -1877,6 +1879,8 @@ describe('ReactIncremental', () => { ); ReactNoop.flush(); expect(ops).toEqual([ + 'ShowLocale {"locale":"sv"}', + 'ShowBoth {"locale":"sv"}', 'Intl {}', 'ShowLocale {"locale":"en"}', 'Router {}', @@ -2648,4 +2652,67 @@ describe('ReactIncremental', () => { 'count:1, name:not brian', ]); }); + + it('does not interrupt for update at same priority', () => { + function Parent(props) { + ReactNoop.yield('Parent: ' + props.step); + return ; + } + + function Child(props) { + ReactNoop.yield('Child: ' + props.step); + return null; + } + + ReactNoop.render(); + ReactNoop.flushThrough(['Parent: 1']); + + // Interrupt at same priority + ReactNoop.render(); + + expect(ReactNoop.flush()).toEqual(['Child: 1', 'Parent: 2', 'Child: 2']); + }); + + it('does not interrupt for update at lower priority', () => { + function Parent(props) { + ReactNoop.yield('Parent: ' + props.step); + return ; + } + + function Child(props) { + ReactNoop.yield('Child: ' + props.step); + return null; + } + + ReactNoop.render(); + ReactNoop.flushThrough(['Parent: 1']); + + // Interrupt at lower priority + ReactNoop.expire(2000); + ReactNoop.render(); + + expect(ReactNoop.flush()).toEqual(['Child: 1', 'Parent: 2', 'Child: 2']); + }); + + it('does interrupt for update at higher priority', () => { + function Parent(props) { + ReactNoop.yield('Parent: ' + props.step); + return ; + } + + function Child(props) { + ReactNoop.yield('Child: ' + props.step); + return null; + } + + ReactNoop.render(); + ReactNoop.flushThrough(['Parent: 1']); + + // Interrupt at higher priority + expect( + ReactNoop.flushSync(() => ReactNoop.render()), + ).toEqual(['Parent: 2', 'Child: 2']); + + expect(ReactNoop.flush()).toEqual([]); + }); });