🫠
Flutter 3.19以上、popとpush時、画面がrebuildする問題
問題
Flutter 3.19.xでpopとpush時に画面がrebuildする
3.19.3にアップグレードした後、画面Aから画面Bにpushして画面Aに戻ると、画面Aのrebuildが発生する。
3.13に戻るとrebuildが発生しないという不思議な現象が発生した。
画面AにModalRoute.of
を使っていることがわかった。
final arguments = ModalRoute.of(context)?.settings.arguments;
問題関連のissues:
原因
直接の原因は3.19でModalRouteに対しての変更
#112567を対応するため
の#130841
このissuesは、主にWEB上でTabキーを押してフォーカスを切り替えることに関連している問題です。
packages/flutter/lib/src/widgets/routes.dart
void didChangeNext(Route<dynamic>? nextRoute) {
super.didChangeNext(nextRoute);
changedInternalState();
}
void didPopNext(Route<dynamic> nextRoute) {
super.didPopNext(nextRoute);
changedInternalState();
}
void changedInternalState() {
super.changedInternalState();
setState(() { /* internal state already changed */ });
_modalBarrier.markNeedsBuild();
// No need to mark dirty if this method is called during build phase.
if (SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks) {
setState(() { /* internal state already changed */ });
_modalBarrier.markNeedsBuild();
}
_modalScope.maintainState = maintainState;
}
didChangeNext
とdidPopNext
は画面的push
和pop
対応している、このPRではchangedInternalState
を呼び出して、setState
が発生する。
setState
内部の説明を省略、簡単に言えばModalRoute.of
を使うのが原因です。
ModalRoute.of
が使われると、内部的には現在のページのBuildContextが依存関係に追加される。
解決案
①
公式の対応を待つ、MediaQuery.sizeOf(context)
みたいに ModalRoute.argumentsOf(context)
にするらしい
ただこれではiOSの締切に間に合わない
②
/// 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;
}
}
カスタムしたModalRouteを使う
③
#130841の対応の一部をコメントアウトする
packages/flutter/lib/src/widgets/routes.dart
+ // @override
+ // void didChangeNext(Route<dynamic>? nextRoute) {
+ // super.didChangeNext(nextRoute);
+ // changedInternalState();
+ // }
+
+ // @override
+ // void didPopNext(Route<dynamic> nextRoute) {
+ // super.didPopNext(nextRoute);
+ // changedInternalState();
+ // }
この対応自体はWEB上でTabキーを押してフォーカスを切り替える問題ので、アプリとしてほぼ影響ないです。
一時の対応として、コメントアウトして、公式の対応を待った方がいいと思う。
# 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
参考:
Discussion