diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 586dd4f7e3..a7ff053d78 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1190,27 +1190,13 @@ src/renderers/shared/fiber/__tests__/ReactIncrementalReflection-test.js * finds no node before insertion and correct node before deletion src/renderers/shared/fiber/__tests__/ReactIncrementalScheduling-test.js -* schedules and flushes animation work -* schedules and flushes animation work for many roots -* flushes all scheduled animation work -* flushes all scheduled animation work for many roots * schedules and flushes deferred work -* schedules and flushes deferred work for many roots -* flushes scheduled deferred work fitting within deadline -* flushes scheduled deferred work fitting within deadline for many roots -* schedules more deferred work if it runs out of time -* schedules more deferred work if it runs out of time with many roots -* flushes late animation work in a deferred callback if it wins -* flushes late animation work in a deferred callback if it wins with many roots -* flushes late animation work in an animation callback if it wins -* flushes late animation work in an animation callback if it wins with many roots -* flushes all work in a deferred callback if it wins -* flushes all work in a deferred callback if it wins with many roots -* flushes root with late deferred work in an animation callback if it wins -* flushes all roots with animation work in an animation callback if it wins -* splits deferred work on multiple roots +* schedules and flushes animation work +* searches for work on other roots once the current root completes +* schedules an animation callback when there`s leftover animation work +* schedules top-level updates in order of priority +* schedules top-level updates with same priority in order of insertion * works on deferred roots in the order they were scheduled -* handles interleaved deferred and animation work * schedules sync updates when inside componentDidMount/Update * can opt-in to deferred/animation scheduling inside componentDidMount/Update * performs Task work even after time runs out diff --git a/src/renderers/noop/ReactNoop.js b/src/renderers/noop/ReactNoop.js index 6e5102859b..90e7500c50 100644 --- a/src/renderers/noop/ReactNoop.js +++ b/src/renderers/noop/ReactNoop.js @@ -304,14 +304,16 @@ var ReactNoop = { log( ' '.repeat(depth + 1) + '~', firstUpdate && firstUpdate.partialState, - firstUpdate.callback ? 'with callback' : '' + firstUpdate.callback ? 'with callback' : '', + '[' + firstUpdate.priorityLevel + ']' ); var next; while (next = firstUpdate.next) { log( ' '.repeat(depth + 1) + '~', next.partialState, - next.callback ? 'with callback' : '' + next.callback ? 'with callback' : '', + '[' + firstUpdate.priorityLevel + ']' ); } } diff --git a/src/renderers/shared/fiber/ReactFiberBeginWork.js b/src/renderers/shared/fiber/ReactFiberBeginWork.js index 35b3570db0..f7442c7bbd 100644 --- a/src/renderers/shared/fiber/ReactFiberBeginWork.js +++ b/src/renderers/shared/fiber/ReactFiberBeginWork.js @@ -542,12 +542,15 @@ module.exports = function( pushTopLevelContextObject(root.context, false); } - if (updateQueue) { - beginUpdateQueue(workInProgress, updateQueue, null, null, null, priorityLevel); - } + pushHostContainer(root.containerInfo); - pushHostContainer(workInProgress.stateNode.containerInfo); - reconcileChildren(current, workInProgress, pendingProps); + if (updateQueue) { + const prevState = workInProgress.memoizedState; + const state = beginUpdateQueue(workInProgress, updateQueue, null, prevState, null, priorityLevel); + const element = state.element; + reconcileChildren(current, workInProgress, element); + workInProgress.memoizedState = state; + } // A yield component is just a placeholder, we can just run through the // next one immediately. diff --git a/src/renderers/shared/fiber/ReactFiberReconciler.js b/src/renderers/shared/fiber/ReactFiberReconciler.js index 0a9b042471..d8af96af6b 100644 --- a/src/renderers/shared/fiber/ReactFiberReconciler.js +++ b/src/renderers/shared/fiber/ReactFiberReconciler.js @@ -98,7 +98,7 @@ getContextForSubtree._injectFiber(function(fiber : Fiber) { module.exports = function(config : HostConfig) : Reconciler { var { - scheduleWork, + scheduleSetState, scheduleUpdateCallback, performWithPriority, batchedUpdates, @@ -113,20 +113,11 @@ module.exports = function(config : HostConfig(config : HostConfig(config : HostConfig(config : HostConfig(config : HostConfig(config : HostConfig(config : HostConfig { ReactNoop.performAnimationWork(() => { ReactNoop.render(); }); - ReactNoop.render(); ReactNoop.flushAnimationPri(); expect(ops).toEqual(['Foo', 'Bar', 'Bar']); diff --git a/src/renderers/shared/fiber/__tests__/ReactIncrementalScheduling-test.js b/src/renderers/shared/fiber/__tests__/ReactIncrementalScheduling-test.js index f1bc165d2f..c00dc89f37 100644 --- a/src/renderers/shared/fiber/__tests__/ReactIncrementalScheduling-test.js +++ b/src/renderers/shared/fiber/__tests__/ReactIncrementalScheduling-test.js @@ -25,6 +25,14 @@ describe('ReactIncrementalScheduling', () => { return { type: 'span', children: [], prop }; } + it('schedules and flushes deferred work', () => { + ReactNoop.render(); + expect(ReactNoop.getChildren()).toEqual([]); + + ReactNoop.flushDeferredPri(); + expect(ReactNoop.getChildren()).toEqual([span('1')]); + }); + it('schedules and flushes animation work', () => { ReactNoop.performAnimationWork(() => { ReactNoop.render(); @@ -35,341 +43,75 @@ describe('ReactIncrementalScheduling', () => { expect(ReactNoop.getChildren()).toEqual([span('1')]); }); - it('schedules and flushes animation work for many roots', () => { - ReactNoop.performAnimationWork(() => { - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - }); - expect(ReactNoop.getChildren('a')).toEqual([]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual([]); + it('searches for work on other roots once the current root completes', () => { + ReactNoop.renderToRootWithID(, 'a'); + ReactNoop.renderToRootWithID(, 'b'); + ReactNoop.renderToRootWithID(, 'c'); + + ReactNoop.flush(); - ReactNoop.flushAnimationPri(); expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]); expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]); }); - it('flushes all scheduled animation work', () => { - ReactNoop.performAnimationWork(() => { - ReactNoop.render(); - }); - ReactNoop.performAnimationWork(() => { - ReactNoop.render(); - }); - expect(ReactNoop.getChildren()).toEqual([]); + it('schedules an animation callback when there`\s leftover animation work', () => { + class Foo extends React.Component { + state = { step: 0 }; + componentDidMount() { + ReactNoop.performAnimationWork(() => { + this.setState({ step: 2 }); + }); + this.setState({ step: 1 }); + } + render() { + return ; + } + } + ReactNoop.render(); + // Flush just enough work to mount the component, but not enough to flush + // the animation update. + ReactNoop.flushDeferredPri(25); + expect(ReactNoop.getChildren()).toEqual([span(1)]); + + // There's more animation work. A callback should have been scheduled. ReactNoop.flushAnimationPri(); - expect(ReactNoop.getChildren()).toEqual([span('2')]); + expect(ReactNoop.getChildren()).toEqual([span(2)]); }); - it('flushes all scheduled animation work for many roots', () => { + it('schedules top-level updates in order of priority', () => { + // Initial render. + ReactNoop.render(); + ReactNoop.flush(); + expect(ReactNoop.getChildren()).toEqual([span(1)]); + + ReactNoop.render(); ReactNoop.performAnimationWork(() => { - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); + ReactNoop.render(); + ReactNoop.render(); + ReactNoop.render(); }); - ReactNoop.performAnimationWork(() => { - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - }); - expect(ReactNoop.getChildren('a')).toEqual([]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual([]); - ReactNoop.flushAnimationPri(); - expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); + // The low pri update should be flushed last, even though it was scheduled + // before the animation updates. + ReactNoop.flush(); + expect(ReactNoop.getChildren()).toEqual([span(5)]); }); - it('schedules and flushes deferred work', () => { - ReactNoop.render(); - expect(ReactNoop.getChildren()).toEqual([]); + it('schedules top-level updates with same priority in order of insertion', () => { + // Initial render. + ReactNoop.render(); + ReactNoop.flush(); + expect(ReactNoop.getChildren()).toEqual([span(1)]); - ReactNoop.flushDeferredPri(); - expect(ReactNoop.getChildren()).toEqual([span('1')]); - }); + ReactNoop.render(); + ReactNoop.render(); + ReactNoop.render(); + ReactNoop.render(); - it('schedules and flushes deferred work for many roots', () => { - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - expect(ReactNoop.getChildren('a')).toEqual([]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual([]); - - ReactNoop.flushDeferredPri(); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]); - }); - - it('flushes scheduled deferred work fitting within deadline', () => { - ReactNoop.render(); - ReactNoop.render(); - expect(ReactNoop.getChildren()).toEqual([]); - - ReactNoop.flushDeferredPri(); - expect(ReactNoop.getChildren()).toEqual([span('2')]); - }); - - it('flushes scheduled deferred work fitting within deadline for many roots', () => { - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - ReactNoop.renderToRootWithID(, 'c'); - expect(ReactNoop.getChildren('a')).toEqual([]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual([]); - - ReactNoop.flushDeferredPri(); - expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); - }); - - it('schedules more deferred work if it runs out of time', () => { - ReactNoop.render(); - ReactNoop.render(); - expect(ReactNoop.getChildren()).toEqual([]); - - ReactNoop.flushDeferredPri(5); - expect(ReactNoop.getChildren()).toEqual([]); - - ReactNoop.flushDeferredPri(10); - expect(ReactNoop.getChildren()).toEqual([]); - - ReactNoop.flushDeferredPri(10 + 5); - expect(ReactNoop.getChildren()).toEqual([span('2')]); - }); - - it('schedules more deferred work if it runs out of time with many roots', () => { - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - ReactNoop.renderToRootWithID(, 'c'); - expect(ReactNoop.getChildren('a')).toEqual([]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual([]); - - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual([]); - - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([]); - - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); - }); - - it('flushes late animation work in a deferred callback if it wins', () => { - // Schedule early deferred - ReactNoop.render(); - // Schedule late animation - ReactNoop.performAnimationWork(() => { - ReactNoop.render(); - }); - expect(ReactNoop.getChildren()).toEqual([]); - - // We only scheduled deferred callback so that's what we get. - // It will flush everything. - ReactNoop.flushDeferredPri(); - expect(ReactNoop.getChildren()).toEqual([span('2')]); - }); - - it('flushes late animation work in a deferred callback if it wins with many roots', () => { - // Schedule early deferred - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - // Schedule late animation - ReactNoop.performAnimationWork(() => { - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - }); - expect(ReactNoop.getChildren('a')).toEqual([]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual([]); - - // We only scheduled deferred callback so that's what we get. - // It will flush everything. - ReactNoop.flushDeferredPri(); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); - }); - - it('flushes late animation work in an animation callback if it wins', () => { - // Schedule early deferred - ReactNoop.render(); - // Schedule late animation - ReactNoop.performAnimationWork(() => { - ReactNoop.render(); - }); - expect(ReactNoop.getChildren()).toEqual([]); - - // Flushing animation should have flushed the animation. - ReactNoop.flushAnimationPri(); - expect(ReactNoop.getChildren()).toEqual([span('2')]); - }); - - it('flushes late animation work in an animation callback if it wins with many roots', () => { - // Schedule early deferred - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - // Schedule late animation - ReactNoop.performAnimationWork(() => { - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - }); - expect(ReactNoop.getChildren('a')).toEqual([]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual([]); - - // Flushing animation should have flushed the animation. - ReactNoop.flushAnimationPri(); - expect(ReactNoop.getChildren('a')).toEqual([]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); - - ReactNoop.flushDeferredPri(); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); - }); - - it('flushes all work in a deferred callback if it wins', () => { - // Schedule early animation - ReactNoop.performAnimationWork(() => { - ReactNoop.render(); - }); - // Schedule late deferred - ReactNoop.render(); - expect(ReactNoop.getChildren()).toEqual([]); - - // Flushing deferred should have flushed both early animation and late deferred work that invalidated it. - // This is not a common case, as animation should generally be flushed before deferred work. - ReactNoop.flushDeferredPri(); - expect(ReactNoop.getChildren()).toEqual([span('2')]); - }); - - it('flushes all work in a deferred callback if it wins with many roots', () => { - // Schedule early animation - ReactNoop.performAnimationWork(() => { - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - }); - // Schedule late deferred - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - expect(ReactNoop.getChildren('a')).toEqual([]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual([]); - - // Flushing deferred should have flushed both early animation and late deferred work that invalidated it. - // This is not a common case, as animation should generally be flushed before deferred work. - ReactNoop.flushDeferredPri(); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); - }); - - it('flushes root with late deferred work in an animation callback if it wins', () => { - // Schedule early animation - ReactNoop.performAnimationWork(() => { - ReactNoop.render(); - }); - // Schedule late deferred - ReactNoop.render(); - expect(ReactNoop.getChildren()).toEqual([]); - - // Flushing animation work flushes everything on this root. - ReactNoop.flushAnimationPri(); - expect(ReactNoop.getChildren()).toEqual([span('2')]); - }); - - it('flushes all roots with animation work in an animation callback if it wins', () => { - // Schedule early animation - ReactNoop.performAnimationWork(() => { - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - }); - // Schedule late deferred - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - expect(ReactNoop.getChildren('a')).toEqual([]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual([]); - - // Flushing animation work flushes all roots with animation work. - ReactNoop.flushAnimationPri(); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([]); - - // Flushing deferred work flushes the root with only deferred work. - ReactNoop.flushDeferredPri(); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); - }); - - it('splits deferred work on multiple roots', () => { - // Schedule one root - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - - // Schedule two roots - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - // First scheduled one gets processed first - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]); - expect(ReactNoop.getChildren('b')).toEqual([]); - expect(ReactNoop.getChildren('c')).toEqual(null); - // Then the second one gets processed - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual(null); - - // Schedule three roots - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - // They get processed in the order they were scheduled - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:3')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([]); - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:3')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:3')]); - expect(ReactNoop.getChildren('c')).toEqual([]); - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:3')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:3')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:3')]); - - // Schedule one root many times - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:6')]); + ReactNoop.flush(); + expect(ReactNoop.getChildren()).toEqual([span(5)]); }); it('works on deferred roots in the order they were scheduled', () => { @@ -402,54 +144,6 @@ describe('ReactIncrementalScheduling', () => { expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); }); - it('handles interleaved deferred and animation work', () => { - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - ReactNoop.flush(); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]); - - // Schedule both deferred and animation work - ReactNoop.renderToRootWithID(, 'a'); - ReactNoop.performAnimationWork(() => { - ReactNoop.renderToRootWithID(, 'b'); - ReactNoop.renderToRootWithID(, 'c'); - }); - // We're flushing deferred work - // Still, roots with animation work are handled first - ReactNoop.flushDeferredPri(15); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:1')]); - ReactNoop.flushDeferredPri(15); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); - - // More deferred and animation work just got scheduled! - ReactNoop.renderToRootWithID(, 'c'); - ReactNoop.performAnimationWork(() => { - ReactNoop.renderToRootWithID(, 'b'); - }); - // Animation is still handled first - ReactNoop.flushDeferredPri(15); - expect(ReactNoop.getChildren('a')).toEqual([span('a:1')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:3')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); - - // Finally we handle deferred root in the order it was scheduled - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:3')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:2')]); - ReactNoop.flushDeferredPri(15 + 5); - expect(ReactNoop.getChildren('a')).toEqual([span('a:2')]); - expect(ReactNoop.getChildren('b')).toEqual([span('b:3')]); - expect(ReactNoop.getChildren('c')).toEqual([span('c:3')]); - }); - it('schedules sync updates when inside componentDidMount/Update', () => { var instance; var ops = []; diff --git a/src/renderers/shared/shared/__tests__/ReactCompositeComponentState-test.js b/src/renderers/shared/shared/__tests__/ReactCompositeComponentState-test.js index 781ab0132b..446fafe747 100644 --- a/src/renderers/shared/shared/__tests__/ReactCompositeComponentState-test.js +++ b/src/renderers/shared/shared/__tests__/ReactCompositeComponentState-test.js @@ -169,16 +169,22 @@ describe('ReactCompositeComponent-state', () => { // componentDidMount() called setState({color:'yellow'}), which is async. // The update doesn't happen until the next flush. ['componentDidMount-end', 'orange'], + ['setState-sunrise', 'orange'], + ['setState-orange', 'orange'], ]; - // The setState callbacks in componentWillMount, and the initial callback - // passed to ReactDOM.render, should be flushed right after component - // did mount: - expected.push( - ['setState-sunrise', 'orange'], // 1 - ['setState-orange', 'orange'], // 2 - ['initial-callback', 'orange'], // 3 - ['shouldComponentUpdate-currentState', 'orange'], + // In Fiber, the initial callback is not enqueued until after any work + // scheduled by lifecycles has flushed (same semantics as a regular setState + // callback outside of a batch). In Stack, the initial render is scheduled + // inside of batchedUpdates, so the callback gets flushed right after + // componentDidMount. + // TODO: We should fix this, in both Stack and Fiber, so that the behavior + // is consistent regardless of whether you're in a batch. + if (!ReactDOMFeatureFlags.useFiber) { + expected.push(['initial-callback', 'orange']); + } + + expected.push(['shouldComponentUpdate-currentState', 'orange'], ['shouldComponentUpdate-nextState', 'yellow'], ['componentWillUpdate-currentState', 'orange'], ['componentWillUpdate-nextState', 'yellow'], @@ -188,6 +194,10 @@ describe('ReactCompositeComponent-state', () => { ['setState-yellow', 'yellow'], ); + if (ReactDOMFeatureFlags.useFiber) { + expected.push(['initial-callback', 'yellow']); + } + expected.push( ['componentWillReceiveProps-start', 'yellow'], // setState({color:'green'}) only enqueues a pending state.