Skip to content

Conversation

@LinXunFeng
Copy link
Member

@LinXunFeng LinXunFeng commented Mar 19, 2024

Added createDependency parameter to ModalRoute.of, which allows developer to freely choose to use dependOnInheritedWidgetOfExactType or getElementForInheritedWidgetOfExactType to obtain ModalRoute.

Releated issue:

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: routes Navigator, Router, and related APIs. labels Mar 19, 2024
/// while it is visible (specifically, if [isCurrent] or [canPop] change value).
@optionalTypeArgs
static ModalRoute<T>? of<T extends Object?>(BuildContext context) {
final _ModalScopeStatus? widget = context.dependOnInheritedWidgetOfExactType<_ModalScopeStatus>();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found this line of code didn't change in 3.19. but why the action is changed.

Copy link
Member Author

@LinXunFeng LinXunFeng Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main reason is that these codes were added in the PR #134554

@override
void didChangeNext(Route<dynamic>? nextRoute) {
super.didChangeNext(nextRoute);
changedInternalState();
}
@override
void didPopNext(Route<dynamic> nextRoute) {
super.didPopNext(nextRoute);
changedInternalState();
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my scenario ,when calling showDialog will also come across such problem as I said in #145136 (comment) , so this case also need to be dealt;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also applies showDialog

@LinXunFeng LinXunFeng changed the title Add the listen parameter to ModalRoute.of Add the createDependency parameter to ModalRoute.of Mar 20, 2024
@LinXunFeng LinXunFeng requested a review from goderbauer March 21, 2024 01:05

/// Obtains the element corresponding to the nearest widget of
/// [_ModalScopeStatus] within the given [context].
@visibleForTesting
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

@LinXunFeng LinXunFeng Mar 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added @protected

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a static method. @protected doesn't make sense here.

final _ModalScopeStatus? widget = context.dependOnInheritedWidgetOfExactType<_ModalScopeStatus>();
static ModalRoute<T>? of<T extends Object?>(
BuildContext context, {
bool createDependency = true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What problem is it solving to not create the dependency? In my experience, this kind of API often ends up being a footgun where people forget to switch this to true when their code evolves and they do actually need to rebuild when ModalRoute changes.

Copy link
Member Author

@LinXunFeng LinXunFeng Mar 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In many cases, people obtain route arguments through ModalRoute.of(context)?.settings.arguments. In this scenario, there is no need to create dependency.

Now after upgrading to 3.19, I found that I obtained the route arguments in Page2 and then pushed to Page3. During the process of Page3 being pushed and popped, the build method of Page2 will be called again because of ModalRoute.of. In this process, it is meaningless for Page2 to re-obtain routing arguments.

2024-03-22.10.08.36.mov

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In many cases, people obtain route arguments through ModalRoute.of(context)?.settings.arguments. In this scenario, there is no need to create dependency.

The settings associated with a route (and with that the arguments) can change, though (see [1]). Not creating a dependency will lead to bugs because widgets that previously read the args will not rebuild with the new args. So, this API will likely be a foot gun. Instead, we could consider an API that only rebuilds when the arguments change. Something like ModalRoute.argumentsOf(context).

[1]

void _updateSettings(RouteSettings newSettings) {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, but sorry I don’t have time to complete it, thanks for reviewing.

@LinXunFeng
Copy link
Member Author

LinXunFeng commented Apr 3, 2024

@goderbauer Hello, will you continue to review it?

If you do not accept the changes in this PR, could you please indicate how to solve unnecessary rebuild caused by use ModalRoute.of(context)?.settings.arguments? This is very important to us, thank you!

@goderbauer
Copy link
Member

Yes, I have this on my list of PRs to review and will get back to it shortly. Sorry for the delay.

@ioma8
Copy link

ioma8 commented Apr 11, 2024

@goderbauer How does it look? This issue is kinda blocking our update of flutter.

@ioma8
Copy link

ioma8 commented Apr 11, 2024

@goderbauer Hello, will you continue to review it?

If you do not accept the changes in this PR, could you please indicate how to solve unnecessary rebuild caused by use ModalRoute.of(context)?.settings.arguments? This is very important to us, thank you!

Have you found any other solution yet?

@LinXunFeng
Copy link
Member Author

Have you found any other solution yet?

@ioma8 We temporarily solve this issue by modifying the flutter source code.

# Enter your local flutter directory
cd /Users/lxf/fvm/versions/3.19.3

# Download patch
curl -O https://raw.githubusercontent.com/LinXunFeng/flutter_assets/main/patch/01_rollbak_3_19_routes_change/0001-Roll-back-changes-to-routes.dart.patch

# Apply patch
git apply 0001-Roll-back-changes-to-routes.dart.patch

Related article: Flutter - 升级3.19之后页面多次rebuild?🤨

@kandevis
Copy link

This issue is blocking us to upgrade to Flutter 3.19.x
The widget tree rebuild issue make performance terrible. @goderbauer Can you continue to review it or put another solution to this issue.

@CoderBuck
Copy link

My temporary solution: replace all instances of ModalRoute.of(context) with MyModalRoute.of(context).

/// replace ModalRoute.of(context)
class MyModalRoute {

  static ModalRoute<dynamic>? of(BuildContext context) {
    ModalRoute<dynamic>? route;
    context.visitAncestorElements((element) {
      if(element.widget.runtimeType.toString() == '_ModalScopeStatus') {
        dynamic widget = element.widget;
        route = widget.route as ModalRoute;
        return false;
      }
      return true;
    });
    return route;
  }
}

@LinXunFeng LinXunFeng closed this Apr 16, 2024
@ghost
Copy link

ghost commented Apr 16, 2024

Close when no one care about this issue =)). LOL

@cjcj125125
Copy link

真的没人在乎么,我很在乎呀,我这个该死的强迫症

@harismairaj
Copy link

harismairaj commented Apr 23, 2024

My temporary solution: replace all instances of ModalRoute.of(context) with MyModalRoute.of(context).

/// replace ModalRoute.of(context)
class MyModalRoute {

  static ModalRoute<dynamic>? of(BuildContext context) {
    ModalRoute<dynamic>? route;
    context.visitAncestorElements((element) {
      if(element.widget.runtimeType.toString() == '_ModalScopeStatus') {
        dynamic widget = element.widget;
        route = widget.route as ModalRoute;
        return false;
      }
      return true;
    });
    return route;
  }
}

It is working for me. Thanks @CoderBuck for the solution.

auto-submit bot pushed a commit that referenced this pull request May 29, 2024
According to previous discussion at #145389 (comment), this change makes `_ModalScopeStatus` an `InheritedModel` rather than an `InheritedWidget`, and provides the following methods.

- `isCurrentOf`
- `canPopOf`
- `settingsOf`

For example, `ModalRoute.of(context)!.settings` could become `ModalRoute.settingsOf(context)` as a performance optimization.
victorsanni pushed a commit to victorsanni/flutter that referenced this pull request May 31, 2024
According to previous discussion at flutter#145389 (comment), this change makes `_ModalScopeStatus` an `InheritedModel` rather than an `InheritedWidget`, and provides the following methods.

- `isCurrentOf`
- `canPopOf`
- `settingsOf`

For example, `ModalRoute.of(context)!.settings` could become `ModalRoute.settingsOf(context)` as a performance optimization.
@Plinzen
Copy link

Plinzen commented Jun 17, 2024

/// replace ModalRoute.of(context)
class MyModalRoute {

  static ModalRoute<dynamic>? of(BuildContext context) {
    ModalRoute<dynamic>? route;
    context.visitAncestorElements((element) {
      if(element.widget.runtimeType.toString() == '_ModalScopeStatus') {
        dynamic widget = element.widget;
        route = widget.route as ModalRoute;
        return false;
      }
      return true;
    });
    return route;
  }
}

Is there also a solution when the code is obfuscated? Since the _ModalScopeStatus class is renamed by obfuscation this check doesn't work on an obfuscated release build.

@LinXunFeng LinXunFeng deleted the modal_route_of_add_listen_param branch February 12, 2025 01:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

f: routes Navigator, Router, and related APIs. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants