diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 85498b39c69..1f3ce1fdc8b 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1294,6 +1294,7 @@ src/renderers/shared/shared/__tests__/ReactCompositeComponentDOMMinimalism-test. src/renderers/shared/shared/__tests__/ReactCompositeComponentState-test.js * should support setting state +* should call componentDidUpdate of children first * should batch unmounts src/renderers/shared/shared/__tests__/ReactEmptyComponent-test.js diff --git a/src/renderers/shared/shared/__tests__/ReactCompositeComponentState-test.js b/src/renderers/shared/shared/__tests__/ReactCompositeComponentState-test.js index 1a12bf360e5..eded0437edf 100644 --- a/src/renderers/shared/shared/__tests__/ReactCompositeComponentState-test.js +++ b/src/renderers/shared/shared/__tests__/ReactCompositeComponentState-test.js @@ -13,6 +13,7 @@ var React; var ReactDOM; +var ReactDOMFeatureFlags; var TestComponent; @@ -22,6 +23,7 @@ describe('ReactCompositeComponent-state', () => { React = require('React'); ReactDOM = require('ReactDOM'); + ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); TestComponent = React.createClass({ peekAtState: function(from, state) { @@ -227,6 +229,90 @@ describe('ReactCompositeComponent-state', () => { expect(stateListener.mock.calls.join('\n')).toEqual(expected.join('\n')); }); + + it('should call componentDidUpdate of children first', () => { + var container = document.createElement('div'); + + var ops = []; + + var child = null; + var parent = null; + + class Child extends React.Component { + state = {bar:false}; + componentDidMount() { + child = this; + } + componentDidUpdate() { + ops.push('child did update'); + } + render() { + return
; + } + } + + var shouldUpdate = true; + + class Intermediate extends React.Component { + shouldComponentUpdate() { + return shouldUpdate; + } + render() { + return ; + } + } + + class Parent extends React.Component { + state = {foo:false}; + componentDidMount() { + parent = this; + } + componentDidUpdate() { + ops.push('parent did update'); + } + render() { + return ; + } + } + + ReactDOM.render(, container); + + ReactDOM.unstable_batchedUpdates(() => { + parent.setState({ foo: true }); + child.setState({ bar: true }); + }); + // When we render changes top-down in a batch, children's componentDidUpdate + // happens before the parent. + expect(ops).toEqual([ + 'child did update', + 'parent did update', + ]); + + shouldUpdate = false; + + ops = []; + + ReactDOM.unstable_batchedUpdates(() => { + parent.setState({ foo: false }); + child.setState({ bar: false }); + }); + // We expect the same thing to happen if we bail out in the middle. + expect(ops).toEqual( + ReactDOMFeatureFlags.useFiber ? + [ + // Fiber works as expected + 'child did update', + 'parent did update', + ] : [ + // Stack treats these as two separate updates and therefore the order + // is inverse. + 'parent did update', + 'child did update', + ] + ); + + }); + it('should batch unmounts', () => { var outer;