RouterOutlet routes persist even when parent route is popped
Opened this issue · 3 comments
Describe the bug
Calling Modular.to.pop() or Navigator.of(context).pop() in a widget wrapping a RouterOutlet doesn't dispose of the RouterOutlet's widget tree. This appears to be specific to RouterOutlets displaying a dynamic route. Each time the dynamic route is pushed and popped, the RouterOutlet builds an additional widget tree.
Environment
Add your flutter doctor -v
[✓] Flutter (Channel stable, 3.19.5, on macOS 14.2.1 23C71 darwin-arm64, locale en-US)
• Flutter version 3.19.5 on channel stable at /Users/zssnyder/Projects/Libraries/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 300451adae (10 weeks ago), 2024-03-27 21:54:07 -0500
• Engine revision e76c956498
• Dart version 3.3.3
• DevTools version 2.31.1
[✗] Android toolchain - develop for Android devices
✗ Unable to locate Android SDK.
Install Android Studio from: https://developer.android.com/studio/index.html
On first launch it will assist you in installing the Android SDK components.
(or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
If the Android SDK has been installed to a custom location, please use
`flutter config --android-sdk` to update to that location.
[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 15F31d
• CocoaPods version 1.15.2
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 4.1)
• Android Studio at /Users/zssnyder/Library/Application
Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/201.6953283/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
[✓] VS Code (version 1.89.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.90.0
[✓] Network resources
• All expected network resources are available.
To Reproduce
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
void main() {
runApp(ModularApp(module: AppModule(), child: const MainApp()));
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
Modular.setInitialRoute('/home');
return MaterialApp.router(
title: "RouterOutlet Test",
routerConfig: Modular.routerConfig,
);
}
}
class AppModule extends Module {
@override
void routes(RouteManager r) {
r.child('/', child: (context) => const HomePage(), children: [
ChildRoute('/home', child: (context) => const ChildPage('0')),
]);
r.module('/child', module: ChildModule());
}
}
class ChildModule extends Module {
@override
void routes(RouteManager r) {
r.child('/', child: (context) => const ParentPage(), children: [
ChildRoute('/:id', child: (context) => ChildPage(r.args.params['id'])),
]);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: const RouterOutlet(),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.arrow_forward_rounded),
onPressed: () {
Modular.to.pushNamed('/child/$id');
setState(() {
id++;
});
},
),
);
}
}
class ParentPage extends StatelessWidget {
const ParentPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back_rounded),
onPressed: () => Modular.to.pop(),
),
),
body: const RouterOutlet(),
);
}
}
class ChildPage extends StatelessWidget {
const ChildPage(this.id, {super.key});
final String id;
@override
Widget build(BuildContext context) {
print(id);
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text(id),
),
);
}
}
Expected behavior
Each time the floating action button is pressed to navigate to the Child Module's route, the "id" passed into the route should be printed once.
Screenshots
Running on iOS Simulator (17.4)
https://github.com/Flutterando/modular/assets/19160564/f9253516-f72f-45be-a92e-d47eb332cb85
Output:
flutter: 0
flutter: 1
flutter: 1
flutter: 2
flutter: 2
flutter: 2
flutter: 3
flutter: 3
flutter: 3
flutter: 3
pubspec.yaml
name: modular_bug
description: "A new Flutter project."
publish_to: 'none'
version: 0.1.0
environment:
sdk: '>=3.3.3 <4.0.0'
dependencies:
flutter:
sdk: flutter
flutter_modular: ^6.3.4
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0
flutter:
uses-material-design: true
@zssnyder I was having the same problem, tested your solution and it worked, thanks!!
But the master
branch, was breaking I had to change to the modular_lite
branch
dependency_overrides:
flutter_modular:
git:
url: https://github.com/zssnyder/flutter_modular.git
ref: modular_lite
path: flutter_modular
modular_core:
git:
url: https://github.com/zssnyder/flutter_modular.git
ref: modular_lite
path: modular_core
same issue
flutter_modular: ^6.3.4
Flutter 3.26.0-0.1.pre • channel beta • https://github.com/flutter/flutter.git
Framework • revision ee624bc4fd (12 days ago) • 2024-09-10 17:41:06 -0500
Engine • revision 059e4e6d8f
Tools • Dart 3.6.0 (build 3.6.0-216.1.beta) • DevTools 2.39.0
class DemoHome extends StatelessWidget {
const DemoHome({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
ElevatedButton(
onPressed: () => Modular.to.pushNamed(Routes.s1),
child: const Text('Scrren1'),
),
ElevatedButton(
onPressed: () => Modular.to.pushNamed(Routes.s2),
child: const Text('Scrren2'),
),
],
),
);
}
}
class DemoPage extends StatelessWidget {
const DemoPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color(0xFF162866),
foregroundColor: Colors.white,
centerTitle: true,
title: const Text('Demo Page'),
leading: const BackButton(color: Colors.white),
),
body: const Center(
child: RouterOutlet(),
),
);
}
}
class Scrren1 extends StatelessWidget {
const Scrren1({super.key});
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
color: Colors.blue,
child: const Text('Scrren1'),
);
}
}
class Scrren2 extends StatelessWidget {
const Scrren2({super.key});
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
color: Colors.green,
child: const Text('Scrren2'),
);
}
}
/// DemoModule
class DemoModule extends Module {
.....
void routes(RouteManager r) {
r.child('demoHome', child: (_) => const DemoHome(), children: []);
r.child(
'demoPage',
child: (_) => const DemoPage(),
children: [
ChildRoute(
'scrren1',
child: (_) => const Scrren1(),
children: [],
),
ChildRoute(
'scrren2',
child: (_) => const Scrren2(),
children: [],
),
],
);
}
}
/// AppModule
class AppModule extends Module {
.....
@override
void routes(RouteManager r) {
r.module(
'/demo',
module: DemoModule(),
transition: TransitionType.rightToLeft,
guards: [],
);
}
}
////
static String demo = '/demo/demoHome';
static String s1 = '/demo/demoPage/scrren1';
static String s2 = '/demo/demoPage/scrren12';