Repository: flutter
Issue: [Proposal] `Router` api allow to replace `state`
Labels: c: new feature,framework,f: routes,c: proposal,P3,team-framework,triaged-framework

## Use case

Imagine a situation where user wants to navigate to `/` then the app starts to check authentication status which is currently `unknown` (_neither loggen in nor logged out_) so I don't want to replace current url **however I want to put some state in history** ([_for instance to detect forward / backward actions_](https://stackoverflow.com/a/8980832/4609658)).

In JS world [History.replaceState](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState)'s 3. parameter `url` is optional to achive this kind of behavior or just by passing `''`, `null`, `undefined`
as the third parameter.

Currently [RouteInformationParser.restoreRouteInformation](https://api.flutter.dev/flutter/widgets/RouteInformationParser/restoreRouteInformation.html) can return `null` to indicate not to update history.

> This may return null, in which case the browser history will not be updated and state restoration is disabled.

[`RouteInformation`](https://api.flutter.dev/flutter/widgets/RouteInformation-class.html)'s [`location` property](https://api.flutter.dev/flutter/widgets/RouteInformation/location.html) can also be `null` however using `null` will throw exception (_what is the meaning of `null`?_).

If I pass an empty string `''` to [`RouteInformation.location`](https://api.flutter.dev/flutter/widgets/RouteInformation/location.html) then it will cause unexpected results like this:

1. User opens app `/`
2. `RouteInformationParser.restoreRouteInformation` returns `RouteInformation(location: '', state: state)` since authentication status is `unknown`
3. browser replaces the `state`
4. authentication status changed so `RouteInformationParser.restoreRouteInformation` returns `RouteInformation(location: '/', state: state)`
5. browser history stack contains two `'/'` instead of one.

## Proposal

If you look at [`PlatformRouteInformationProvider`](https://api.flutter.dev/flutter/widgets/PlatformRouteInformationProvider-class.html)'s current implementation:
```dart
  @override
  void routerReportsNewRouteInformation(RouteInformation routeInformation, {RouteInformationReportingType type = RouteInformationReportingType.none}) {
    final bool replace =
      type == RouteInformationReportingType.neglect ||
      (type == RouteInformationReportingType.none &&
       _valueInEngine.location == routeInformation.location);
    SystemNavigator.selectMultiEntryHistory();
    SystemNavigator.routeInformationUpdated(
      location: routeInformation.location!,
      state: routeInformation.state,
      replace: replace,
    );
    _value = routeInformation;
    _valueInEngine = routeInformation;
  }
```

1. Documentation should clarify what `null` means in `RouteInformation.location`.
2. `_value` / `_valueInEngine` shouldn't save `RouteInformation` if it's location is `''` just copy the old one with the new `state`.
3. `final bool replace` should handle specials cases like when `RouteInformation.location` is `''` or `null`.

This is a possible implementation:
```dart
  @override
  void routerReportsNewRouteInformation(
    RouteInformation routeInformation, {
    RouteInformationReportingType type = RouteInformationReportingType.none,
  }) {
    final isEmptyLocation = routeInformation.location == null || routeInformation.location == '';

    final replace = type == RouteInformationReportingType.neglect ||
        (type == RouteInformationReportingType.none && (isEmptyLocation || _valueInEngine.location == routeInformation.location));
    SystemNavigator.selectMultiEntryHistory();
    SystemNavigator.routeInformationUpdated(
      // in case of [isEmptyLocation] we can also use old location [_valueInEngine.location!]
      location: isEmptyLocation ? '' : routeInformation.location!,
      state: routeInformation.state,
      replace: replace,
    );

    // TODO: _valueInEngine.copyWith(state: routeInformation.state) would be much nicer
    final newRouteInformation = isEmptyLocation
        ? RouteInformation(
            location: _valueInEngine.location,
            state: routeInformation.state,
          )
        : routeInformation;

    _value = newRouteInformation;
    _valueInEngine = newRouteInformation;
  }
```