1313
1414var React ;
1515var ReactDOM ;
16+ var ReactDOMFeatureFlags ;
1617
1718var TestComponent ;
1819
@@ -22,6 +23,7 @@ describe('ReactCompositeComponent-state', () => {
2223 React = require ( 'React' ) ;
2324
2425 ReactDOM = require ( 'ReactDOM' ) ;
26+ ReactDOMFeatureFlags = require ( 'ReactDOMFeatureFlags' ) ;
2527
2628 TestComponent = React . createClass ( {
2729 peekAtState : function ( from , state ) {
@@ -227,6 +229,90 @@ describe('ReactCompositeComponent-state', () => {
227229 expect ( stateListener . mock . calls . join ( '\n' ) ) . toEqual ( expected . join ( '\n' ) ) ;
228230 } ) ;
229231
232+
233+ it ( 'should call componentDidUpdate of children first' , ( ) => {
234+ var container = document . createElement ( 'div' ) ;
235+
236+ var ops = [ ] ;
237+
238+ var child = null ;
239+ var parent = null ;
240+
241+ class Child extends React . Component {
242+ state = { bar :false } ;
243+ componentDidMount ( ) {
244+ child = this ;
245+ }
246+ componentDidUpdate ( ) {
247+ ops . push ( 'child did update' ) ;
248+ }
249+ render ( ) {
250+ return < div /> ;
251+ }
252+ }
253+
254+ var shouldUpdate = true ;
255+
256+ class Intermediate extends React . Component {
257+ shouldComponentUpdate ( ) {
258+ return shouldUpdate ;
259+ }
260+ render ( ) {
261+ return < Child /> ;
262+ }
263+ }
264+
265+ class Parent extends React . Component {
266+ state = { foo :false } ;
267+ componentDidMount ( ) {
268+ parent = this ;
269+ }
270+ componentDidUpdate ( ) {
271+ ops . push ( 'parent did update' ) ;
272+ }
273+ render ( ) {
274+ return < Intermediate /> ;
275+ }
276+ }
277+
278+ ReactDOM . render ( < Parent /> , container ) ;
279+
280+ ReactDOM . unstable_batchedUpdates ( ( ) => {
281+ parent . setState ( { foo : true } ) ;
282+ child . setState ( { bar : true } ) ;
283+ } ) ;
284+ // When we render changes top-down in a batch, children's componentDidUpdate
285+ // happens before the parent.
286+ expect ( ops ) . toEqual ( [
287+ 'child did update' ,
288+ 'parent did update' ,
289+ ] ) ;
290+
291+ shouldUpdate = false ;
292+
293+ ops = [ ] ;
294+
295+ ReactDOM . unstable_batchedUpdates ( ( ) => {
296+ parent . setState ( { foo : false } ) ;
297+ child . setState ( { bar : false } ) ;
298+ } ) ;
299+ // We expect the same thing to happen if we bail out in the middle.
300+ expect ( ops ) . toEqual (
301+ ReactDOMFeatureFlags . useFiber ?
302+ [
303+ // Fiber works as expected
304+ 'child did update' ,
305+ 'parent did update' ,
306+ ] : [
307+ // Stack treats these as two separate updates and therefore the order
308+ // is inverse.
309+ 'parent did update' ,
310+ 'child did update' ,
311+ ]
312+ ) ;
313+
314+ } ) ;
315+
230316 it ( 'should batch unmounts' , ( ) => {
231317 var outer ;
232318
0 commit comments