@@ -1312,6 +1312,46 @@ describe('ReactUpdates', () => {
1312
1312
ReactDOM . render ( < Foo /> , container ) ;
1313
1313
} ) ;
1314
1314
1315
+ it ( 'resets the update counter for unrelated updates' , ( ) => {
1316
+ const container = document . createElement ( 'div' ) ;
1317
+ const ref = React . createRef ( ) ;
1318
+
1319
+ class EventuallyTerminating extends React . Component {
1320
+ state = { step : 0 } ;
1321
+ componentDidMount ( ) {
1322
+ this . setState ( { step : 1 } ) ;
1323
+ }
1324
+ componentDidUpdate ( ) {
1325
+ if ( this . state . step < limit ) {
1326
+ this . setState ( { step : this . state . step + 1 } ) ;
1327
+ }
1328
+ }
1329
+ render ( ) {
1330
+ return this . state . step ;
1331
+ }
1332
+ }
1333
+
1334
+ let limit = 55 ;
1335
+ expect ( ( ) => {
1336
+ ReactDOM . render ( < EventuallyTerminating ref = { ref } /> , container ) ;
1337
+ } ) . toThrow ( 'Maximum' ) ;
1338
+
1339
+ // Verify that we don't go over the limit if these updates are unrelated.
1340
+ limit -= 10 ;
1341
+ ReactDOM . render ( < EventuallyTerminating ref = { ref } /> , container ) ;
1342
+ expect ( container . textContent ) . toBe ( limit . toString ( ) ) ;
1343
+ ref . current . setState ( { step : 0 } ) ;
1344
+ expect ( container . textContent ) . toBe ( limit . toString ( ) ) ;
1345
+ ref . current . setState ( { step : 0 } ) ;
1346
+ expect ( container . textContent ) . toBe ( limit . toString ( ) ) ;
1347
+
1348
+ limit += 10 ;
1349
+ expect ( ( ) => {
1350
+ ref . current . setState ( { step : 0 } ) ;
1351
+ } ) . toThrow ( 'Maximum' ) ;
1352
+ expect ( ref . current ) . toBe ( null ) ;
1353
+ } ) ;
1354
+
1315
1355
it ( 'does not fall into an infinite update loop' , ( ) => {
1316
1356
class NonTerminating extends React . Component {
1317
1357
state = { step : 0 } ;
@@ -1337,6 +1377,46 @@ describe('ReactUpdates', () => {
1337
1377
} ) . toThrow ( 'Maximum' ) ;
1338
1378
} ) ;
1339
1379
1380
+ it ( 'can recover after falling into an infinite update loop' , ( ) => {
1381
+ class NonTerminating extends React . Component {
1382
+ state = { step : 0 } ;
1383
+ componentDidMount ( ) {
1384
+ this . setState ( { step : 1 } ) ;
1385
+ }
1386
+ componentDidUpdate ( ) {
1387
+ this . setState ( { step : 2 } ) ;
1388
+ }
1389
+ render ( ) {
1390
+ return this . state . step ;
1391
+ }
1392
+ }
1393
+
1394
+ class Terminating extends React . Component {
1395
+ state = { step : 0 } ;
1396
+ componentDidMount ( ) {
1397
+ this . setState ( { step : 1 } ) ;
1398
+ }
1399
+ render ( ) {
1400
+ return this . state . step ;
1401
+ }
1402
+ }
1403
+
1404
+ const container = document . createElement ( 'div' ) ;
1405
+ expect ( ( ) => {
1406
+ ReactDOM . render ( < NonTerminating /> , container ) ;
1407
+ } ) . toThrow ( 'Maximum' ) ;
1408
+
1409
+ ReactDOM . render ( < Terminating /> , container ) ;
1410
+ expect ( container . textContent ) . toBe ( '1' ) ;
1411
+
1412
+ expect ( ( ) => {
1413
+ ReactDOM . render ( < NonTerminating /> , container ) ;
1414
+ } ) . toThrow ( 'Maximum' ) ;
1415
+
1416
+ ReactDOM . render ( < Terminating /> , container ) ;
1417
+ expect ( container . textContent ) . toBe ( '1' ) ;
1418
+ } ) ;
1419
+
1340
1420
it ( 'does not fall into an infinite error loop' , ( ) => {
1341
1421
function BadRender ( ) {
1342
1422
throw new Error ( 'error' ) ;
0 commit comments