# Route transition record and transition delegate updates

> Changes to the rule on how transition delegate resolve route transition.




:::important
These breaking change docs are accurate, as of the release
under which they are published. Over time, the
workarounds described here might become inaccurate.
We don't, in general, keep these breaking change docs up
to date as of each release.

The [breaking change index file](/release/breaking-changes)
lists the docs created for each release.
:::


## Summary

A new boolean getter `isWaitingForExitingDecision` was added
to the route transition record and the `isEntering` getter
was renamed to `isWaitingForEnteringDecision`.
In the `resolve()` method for the transition delegate,
use the `isWaitingForExitingDecision` to check if an exiting
route actually needs an explicit decision on how to transition
off the screen. If you try to make a decision for an existing route
that _isn't_ waiting for a decision, Flutter throws an assertion error.

## Context

When the navigator receives a new list of pages, it tries to update its
current routes stack to match the list. However, it requires explicit
decisions on how to transition the route on and off the screen.
Previously, routes that were not in the new list required decisions
on how to transition off the screen. However, we later found out
this is not always true. If a route is popped,
but is still waiting for the popping animation to finish,
this route would sit in the navigator routes stack until
the animation was done. If a page update occurred during this time,
this route exits but doesn't require a decision
on how to transition off the screen. Therefore,
`isWaitingForExitingDecision` was added to cover that case.

The `isEntering` getter is also renamed to
`isWaitingForEnteringDecision` to be more descriptive,
and also to make the naming more consistent.

## Migration guide

If you implement your own transition delegate, you need to check the
exiting routes using the getter `isWaitingForExitingDecision` before you
call `markForPop`, `markForComplete`, or `markForRemove` on them.
You also need to rename all the references from `isEntering` to
`isWaitingForEnteringDecision`.

Code before migration:

```dart
import 'package:flutter/widgets.dart';

class NoAnimationTransitionDelegate extends TransitionDelegate<void> {
  @override
  Iterable<RouteTransitionRecord> resolve({
    List<RouteTransitionRecord> newPageRouteHistory,
    Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
    Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
  }) {
    final List<RouteTransitionRecord> results = <RouteTransitionRecord>[];

    for (final RouteTransitionRecord pageRoute in newPageRouteHistory) {
      if (pageRoute.isEntering) {
        pageRoute.markForAdd();
      }
      results.add(pageRoute);

    }
    for (final RouteTransitionRecord exitingPageRoute in locationToExitingPageRoute.values) {
      exitingPageRoute.markForRemove();
      final List<RouteTransitionRecord> pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute];
      if (pagelessRoutes != null) {
        for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
          pagelessRoute.markForRemove();
        }
      }
      results.add(exitingPageRoute);

    }
    return results;
  }
}
```

Code after migration:

```dart
import 'package:flutter/widgets.dart';

class NoAnimationTransitionDelegate extends TransitionDelegate<void> {
  @override
  Iterable<RouteTransitionRecord> resolve({
    List<RouteTransitionRecord> newPageRouteHistory,
    Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
    Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
  }) {
    final List<RouteTransitionRecord> results = <RouteTransitionRecord>[];

    for (final RouteTransitionRecord pageRoute in newPageRouteHistory) {
      // Renames isEntering to isWaitingForEnteringDecision.
      if (pageRoute.isWaitingForEnteringDecision) {
        pageRoute.markForAdd();
      }
      results.add(pageRoute);

    }
    for (final RouteTransitionRecord exitingPageRoute in locationToExitingPageRoute.values) {
      // Checks the isWaitingForExitingDecision before calling the markFor methods.
      if (exitingPageRoute.isWaitingForExitingDecision) {
        exitingPageRoute.markForRemove();
        final List<RouteTransitionRecord> pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute];
        if (pagelessRoutes != null) {
          for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
            pagelessRoute.markForRemove();
          }
        }
      }
      results.add(exitingPageRoute);

    }
    return results;
  }
}
```

## Timeline

Landed in version: 1.18.0<br>
In stable release: 1.20

## References

API documentation:

* [`Navigator`][]
* [`TransitionDelegate`][]
* [`RouteTransitionRecord`][]

Relevant issue:

* [Issue 45938: Navigator 2.0][]

Relevant PR:

* [PR 55998][]: Fixes the navigator pages update crash
  when there is still a route waiting


[Issue 45938: Navigator 2.0]: https://github.com/flutter/flutter/issues/45938
[`Navigator`]: https://api.flutter.dev/flutter/widgets/Navigator-class.html
[PR 55998]: https://github.com/flutter/flutter/pull/55998
[`TransitionDelegate`]: https://api.flutter.dev/flutter/widgets/TransitionDelegate-class.html
[`RouteTransitionRecord`]: https://api.flutter.dev/flutter/widgets/RouteTransitionRecord-class.html

