Right way to handle navigation using BLoC

前端 未结 1 1470
情话喂你
情话喂你 2021-02-05 16:34

Hello guys I\'m using BLoC for app I\'m currently developing but there some cases which I\'m clueless like when you do login you fire API call and wait for result naturally I wo

相关标签:
1条回答
  • 2021-02-05 16:51

    Edit: After a few months with this solution in place, I noticed that there are a few problems with it:

    1. Android hardware back button does not work
    2. The app resets when you toggle "inspect" mode.
    3. No transitions possible
    4. No guarantee that no forbidden route is displayed

    So I no longer recommend using this approach!


    For normal user-initiated navigation, you don't need the BLoC pattern at all. Just use the Navigator.

    Login is a special case. Following the BLoC pattern, it would make sense to provide a isAuthenticated stream:

    abstract class MyBloc {
      Stream<bool> get isAuthenticated;
    }
    

    Your app will probably have 2 different named route trees: One for logged in users, and one for anonymous users:

    final Map<String, WidgetBuilder> anonymousRoutes = {
      '/': (context) => new LoginScreen(), // default for anon
      '/register': (context) => new RegisterScreen(),
    };
    
    final Map<String, WidgetBuilder> authenticatedRoutes = {
      '/': (context) => new HomeScreen(), // default for logged in
      '/savings': (context) => new SavingsScreen(),
      // ...
    };
    

    Usually the Navigator and its named routes are tightly coupled to the MaterialApp, but you can also define your own that is rebuilt when the isAuthenticated stream is updated:

    class MyApp extends StatelessWidget {
      const MyApp({Key key, this.bloc}) : super(key: key);
    
      final MyBloc bloc;
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          builder: (BuildContext context, Widget child) {
            return StreamBuilder<bool>(
              stream: bloc.isAuthenticated,
              builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
                if (!snapshot.hasData) {
                  return Text('loading...');
                }
    
                bool isAuthenticated = snapshot.data;
                return _buildNavigator(isAuthenticated);
              },
            );
          },
        );
      }
    }
    
    Navigator _buildNavigator(bool isAuthenticated) {
      // different route tree and different default route depending on auth state
      final routes = isAuthenticated ? authenticatedRoutes : anonymousRoutes;
    
      return Navigator(
        key: new ValueKey(isAuthenticated),
        onGenerateRoute: (RouteSettings settings) {
          final name = settings.name;
          return new MaterialPageRoute(
            builder: routes[name],
            settings: settings,
          );
        },
        onUnknownRoute: (RouteSettings settings) {
          throw Exception('unknown route');
        },
      );
    }
    

    Sadly right now (2018-07-14) there are a 2 conflicting asserts in the Flutter code which you have to remove to make the code above work (you can just edit it with your IDE):

    Line 93 and 96 in packages\flutter\lib\src\widgets\app.dart

    //assert(navigatorObservers != null),
    //assert(onGenerateRoute != null || navigatorObservers == const <NavigatorObserver>[]),
    
    0 讨论(0)
提交回复
热议问题