flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
166.3k stars 27.52k forks source link

[go_router] GoRouterState.error is only populated for errorBuilder when the route is not found #158504

Open slaci opened 2 days ago

slaci commented 2 days ago

Steps to reproduce

The GoRouterState object has an error property which I would expect to hold a GoException when I open a non-existing route. Currently this exception is only available in errorBuilder and errorPageBuilder, but always null in onException and redirect.

My use case would be: I try to protect most of the screens with authentication by the redirect callback, but I can't make error screens unprotected as state.error is always null and nothing else indicates that I am on an error screen. Only buildError receives the error, but that is too late as redirect will redirect back the user before that. This can be easily triggered by deep links sadly.

To reproduce please run my attached code sample. As onException and errorBuilder are mutually exclusive, one of them is commented out.

I'm using go_router: 14.4.1 with flutter 3.24.4 on Android (but I don't think it is platform dependant, however I don't know and care about web or any non-mobile).

Expected results

The GoRouterState's error property should be non-null when the matched location is not registered among the possible routes. In the example code all errors should be like the following after tapping the Open a non-existing route button:

/404: GoException: no routes for lcoation: /404

Actual results

The GoRouterState's error property is null when opening a non-existing route. In the example app all errors are like this:

/404: No error

Code sample

Code sample ```dart import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; void main() => runApp(const MyApp()); final _errorNotifier = ValueNotifier(''); final _redirectErrorNotififer = ValueNotifier(''); extension on GoRouterState { String get errorMsg => '$matchedLocation: ${error ?? 'No error'}'; } final _router = GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => const HomeScreen(), ), ], redirect: (context, state) { _redirectErrorNotififer.value = state.errorMsg; return null; }, onException: (context, state, router) => _errorNotifier.value = state.errorMsg, // errorBuilder: (context, state) => HomeScreen(error: state.errorMsg), ); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: _router, ); } } class HomeScreen extends StatefulWidget { final String? error; const HomeScreen({super.key, this.error}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { String? _goRouterOnExceptionError; String? _goRouterRedirectError; late final _commonErrorLabel; @override void initState() { super.initState(); _goRouterOnExceptionError = widget.error; _commonErrorLabel = widget.error != null ? 'buildError' : 'onException'; _errorNotifier.addListener(_onExceptionErrorListener); _redirectErrorNotififer.addListener(_redirectErrorListener); } @override void dispose() { _errorNotifier.removeListener(_onExceptionErrorListener); _redirectErrorNotififer.removeListener(_redirectErrorListener); super.dispose(); } void _onExceptionErrorListener() { setState(() { _goRouterOnExceptionError = _errorNotifier.value; }); } void _redirectErrorListener() { setState(() { _goRouterRedirectError = _redirectErrorNotififer.value; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home Screen')), body: SizedBox.expand( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ ..._errorMessage( context, _commonErrorLabel, _goRouterOnExceptionError), ..._errorMessage(context, 'redirect', _goRouterRedirectError), ElevatedButton( onPressed: () => context.push('/404'), child: const Text('Open a non-existing route'), ), ], ), ), ); } List _errorMessage( BuildContext context, String label, String? message, ) { if (message == null) { return const []; } final theme = Theme.of(context); final colorScheme = theme.colorScheme; return [ Text(label, style: theme.textTheme.labelLarge), ColoredBox( color: colorScheme.error, child: Padding( padding: const EdgeInsets.all(8.0), child: Text( message, style: TextStyle(color: colorScheme.onError), ), ), ), const SizedBox(height: 15.0), ]; } } ```

Screenshots or Video

No response

Logs

No response

Flutter Doctor output

Doctor output ```console [✓] Flutter (Channel stable, 3.24.4, on macOS 15.1 24B83 darwin-arm64, locale en-HU) • Flutter version 3.24.4 on channel stable at /Users/macbookpro/devtools/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 603104015d (3 weeks ago), 2024-10-24 08:01:25 -0700 • Engine revision db49896cf2 • Dart version 3.5.4 • DevTools version 2.37.3 [✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0) • Android SDK at /Users/macbookpro/devtools/android_sdk • Platform android-34, build-tools 34.0.0 • ANDROID_SDK_ROOT = /Users/macbookpro/devtools/android_sdk • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 21.0.3+-79915917-b509.11) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 16.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 16B40 • CocoaPods version 1.16.1 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 2024.2) • 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 21.0.3+-79915917-b509.11) [✓] VS Code (version 1.95.2) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.100.0 [✓] Connected device (4 available) • SM S906U1 (mobile) • RFCT20EQM0M • android-arm64 • Android 14 (API 34) • macOS (desktop) • macos • darwin-arm64 • macOS 15.1 24B83 darwin-arm64 • Mac Designed for iPad (desktop) • mac-designed-for-ipad • darwin • macOS 15.1 24B83 darwin-arm64 • Chrome (web) • chrome • web-javascript • Google Chrome 130.0.6723.117 ! Error: Browsing on the local area network for László’s iPhone. Ensure the device is unlocked and attached with a cable or associated with the same local area network as this Mac. The device must be opted into Developer Mode to connect wirelessly. (code -27) [✓] Network resources • All expected network resources are available. • No issues found! ```
huycozy commented 1 day ago

Reproduced the issue using the latest package version go_router: ^14.6.0 on Flutter master version 3.27.0-1.0.pre.470. Thanks for the report.