-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
This comes back to this issue #114234 and this PR flutter/packages#2747.
Before the keys of pages being pushed then replaced were:
[<'/family/:fid-p1'>] // <- Pushed
[<'/family/:fid'>] // <- Replace
[<'/family/:fid'>] // <- Replace
[<'/family/:fid'>] // <- Replace
...
and I thought the pages keys should have been (what was done in flutter/packages#2747)
[<'/family/:fid-p1'>] // <- Pushed
[<'/family/:fid-p2'>] // <- Replace
[<'/family/:fid-p3'>] // <- Replace
[<'/family/:fid-p4'>] // <- Replace
...
because the example given in #114234 was with a Dialog and it wasn't rebuilding when the same key was reused.
But after more investigation, it looks like it should have rebuilt when the same key was reused and this might be a bug with the dialog route itself because it doesn't rebuild when it should. See #115639
So now, because the keys are different after a replace, the state is lost when it is being used.
So I think the keys of the page should instead be (the key of the popped page should be reused when possible to preserve the state of the widgets).
[<'/family/:fid-p1'>] // <- Pushed
[<'/family/:fid-p1'>] // <- Replace
[<'/family/:fid-p1'>] // <- Replace
[<'/family/:fid-p1'>] // <- Replace
...
Steps to Reproduce
- Execute
flutter runon the code sample see "Code sample" section below - Click on a todo in the todos list
- Go left and/or right to use
replace. - Notice that the state is lost:
now(set in theinitState) displays a different time on each page.
Expected results:
The state should be preserved when possible
Actual results:
The state is not preserved.
Code sample
Or you can checkout
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
void main() {
runApp(const MyApp());
}
class Todo {
const Todo({
required this.id,
required this.description,
});
factory Todo.fromIndex(int index) {
return Todo(
id: index,
description: 'Todo $index',
);
}
final int id;
final String description;
}
final router = GoRouter(
initialLocation: '/todos',
routes: [
GoRoute(
path: '/todos',
builder: (_, __) => const TodosScreen(),
routes: [
GoRoute(
path: ':id',
builder: (_, state) {
final uri = Uri.parse(state.location);
final id = int.parse(uri.pathSegments.last);
return TodoScreen(id: id);
}),
],
),
],
);
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: router,
);
}
}
class TodosScreen extends StatelessWidget {
const TodosScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Todos'),
),
body: ListView.builder(
itemBuilder: (context, index) => ListTile(
title: Text(Todo.fromIndex(index).description),
onTap: () => context.go('/todos/$index'),
),
),
);
}
}
class TodoScreen extends StatefulWidget {
const TodoScreen({
required this.id,
super.key,
});
final int id;
@override
State<TodoScreen> createState() => _TodoScreenState();
}
class _TodoScreenState extends State<TodoScreen> {
late final DateTime now;
@override
void initState() {
super.initState();
now = DateTime.now();
}
@override
Widget build(BuildContext context) {
final todo = Todo.fromIndex(widget.id);
return Scaffold(
appBar: AppBar(
title: Text('Todo ${todo.id}'),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: () {
router.replace('/todos/${widget.id - 1}');
},
icon: const Icon(Icons.arrow_back),
),
Expanded(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Todo ${todo.id}: ${todo.description}'),
Text('Now: $now')
],
),
),
),
IconButton(
onPressed: () {
router.replace('/todos/${widget.id + 1}');
},
icon: const Icon(Icons.arrow_forward),
),
],
),
);
}
}Logs
Launching lib/main.dart on macOS in debug mode...
Building macOS application...
Syncing files to device macOS... 113ms
Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
💪 Running with sound null safety 💪
An Observatory debugger and profiler on macOS is available at: http://127.0.0.1:64569/LEROT4Ndx0w=/
The Flutter DevTools debugger and profiler on macOS is available at:
http://127.0.0.1:9101?uri=http://127.0.0.1:64569/LEROT4Ndx0w=/
Analyzing flutter_app_stable...
No issues found! (ran in 5.8s)
[✓] Flutter (Channel stable, 3.3.8, on macOS 11.6.8 20G730 darwin-x64, locale en-GB)
• Flutter version 3.3.8 on channel stable at /Users/valentin/flutter/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 52b3dc25f6 (2 weeks ago), 2022-11-09 12:09:26 +0800
• Engine revision 857bd6b74c
• Dart version 2.18.4
• DevTools version 2.15.0
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
• Android SDK at /usr/local/Caskroom/android-sdk/4333796
• Platform android-33, build-tools 30.0.3
• Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 13C100
• CocoaPods version 1.11.3
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2021.1)
• Android Studio at /Applications/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 11.0.11+0-b60-7590822)
[✓] VS Code (version 1.73.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.52.0
[✓] Connected device (2 available)
• macOS (desktop) • macos • darwin-x64 • macOS 11.6.8 20G730 darwin-x64
• Chrome (web) • chrome • web-javascript • Google Chrome 107.0.5304.110
[✓] HTTP Host Availability
• All required HTTP hosts are available
• No issues found!