I new a bloc/cubit pattern, before I used provider, getx and I want to ask something.
This application have nearly 40 pages and I want to use bloc just 10 pages and close bloc instance when is last page is closed.
Example page 1, I initialize bloc, and it is initialized on the other pages (2, 3, 4...9) will use same bloc/cubit instance and 10 page close bloc instance close
This is router class and cubit initialize here
class Router {
static Route<dynamic> generateRoute(RouteSettings settings) {
final RegisterCubit _registerCubit = RegisterCubit();
switch (settings.name) {
case welcomeRoute:
return MaterialPageRoute(builder: (_) => WelcomePage());
case loginRoute:
return MaterialPageRoute(builder: (_) => LoginPage());
case homeRoute:
return MaterialPageRoute(builder: (_) => HomePage());
case referanceCodePreview:
return MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: _registerCubit,
child: ReferancaCodePreviewView(),
));
case registerOne:
return MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: _registerCubit,
child: RegisterPageOne(),
));
case registerTwo:
return MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: _registerCubit,
child: RegisterPageOTwo(),
));
case registerThree:
return MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: _registerCubit,
child: RegisterPageOThree(),
));
case registerFour:
return MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: _registerCubit,
child: RegisterPageFour(),
));
case registerFive:
return MaterialPageRoute(
builder: (a) => BlocProvider.value(
value: _registerCubit,
child: RegisterPageFive(),
));
This page four and this page not listen to _registerCubit
class RegisterPageFour extends StatefulWidget {
RegisterPageFour({Key? key}) : super(key: key);
#override
State<RegisterPageFour> createState() => _RegisterPageFourState();
}
class _RegisterPageFourState extends State<RegisterPageFour> with
ImageSelectPicker {
#override
Widget build(BuildContext context) {
return BlocConsumer<RegisterCubit, RegisterState>(
listener: (contex, state) {},
builder: (context, state) {
return buildScaffold(context, state);
},
);
}
Navigation PageFour
CustomButton(
buttonWidth: MediaQuery.of(context).size.width,
onPress: () => Navigator.pushNamed(context, "/registerFour"),
title: "İleri"),
Can you help me this issue ?
final RegisterCubit _registerCubit = RegisterCubit();
I suggest you to create object of RegisterCubit outside of generateRoute function.
Something like this,
class Router {
final RegisterCubit _registerCubit = RegisterCubit();
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
}
Related
I am trying to provide a local bloc to a new page, I found some way to do this by using an anonymous route but it doesn't look elegant
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return BlocProvider.value(
value: context.bloc<MyBloc>(),
child: NewPage());
}),
);
What I want is to do the same thing but using a named route and without creating a global bloc as I simply can't
Create app_router.dart file.
app_router.dart
class AppRouter {
final LocalBloc _localBloc = LocalBloc();
Route onGenerateRoute(RouteSettings routeSettings) {
switch (routeSettings.name) {
case '/':
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _localBloc,
child: Home(),
),
);
case '/page1':
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _localBloc,
child: Page1(),
),
);
case '/page2':
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _localBloc,
child: Pag2(),
),
);
}
}
}
Then in your main.dart file
Add onGenerateRoute
final AppRouter _appRouter = AppRouter();
MaterialApp(
title: 'My App',
onGenerateRoute: _appRouter.onGenerateRoute,
),),
In your navigation, you can do this:
Navigator.of(context).pushNamed('/page1');
i am now doing a flutter project. and i use cubit for state management. for navigation i had made a file for routing.using generate route. i have given the router file code below. does anyone had an idea about this.i used block providers to give cubit and navigated to pages using named route.i works when we manually type the path in the browser tab and when we pressed back the url path is not refreshed.
class AppRouter {
/* ADD REPOSITORY TO APP ROUTER */
/* ADD REPOSITORY TO APP ROUTER */
Repository repository;
AppRouter() {
repository = new Repository(apiService: ApiService());
}
Route generateRoute(RouteSettings settings) {
switch (settings.name) {
case "/":
return MaterialPageRoute(
settings: RouteSettings(name: '/'),
builder: (_) => MultiBlocProvider(providers: [
BlocProvider<HomeCubit>(
create: (BuildContext context) {
return HomeCubit(repository: repository);
},
),
BlocProvider<UserCubit>(
create: (BuildContext context) {
return UserCubit(repository: repository);
},
)
],child:SplashScreen()
case "/register":
return MaterialPageRoute(
settings: RouteSettings(name: '/REGISTER'),
builder: (_) => MultiBlocProvider(providers: [
BlocProvider<HomeCubit>(
create: (BuildContext context) {
return HomeCubit(repository: repository);
},
),
BlocProvider<SearchCubit>(
create: (BuildContext context) =>
SearchCubit(repository: repository),
),
BlocProvider<UserCubit>(
create: (BuildContext context) =>
UserCubit(repository: repository),
)
], child: RegisterScreen()));
case '/signin':
return MaterialPageRoute(
builder: (_) => BlocProvider(
create: (BuildContext context) =>
UserCubit(repository: repository),
child: SigninScreen()),
settings: RouteSettings(name: '/signin'));
default:
return MaterialPageRoute(builder: (_) {
return Scaffold(
body: Center(
child: Text('Error! No route Found...',
style: TextStyle(color: Colors.white,fontWeight:FontWeight.bold),),
),
);
});
}
}
}
I'm using Generated Routes with Flutter, and I would like to share blocs between them.
But I think that maybe the example solution might not scale the best, since the blocs are instantiated with the router.
Is there a way to instantiate them only when the user access that route?
class AppRouter {
final _counterBloc = CounterBloc();
Route onGenerateRoute(RouteSettings settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: _counterBloc,
child: HomePage(),
),
);
case '/counter':
return MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: _counterBloc,
child: CounterPage(),
),
);
default:
return null;
}
}
}
Got it! Flutter has a new keyword called late to do this without any boilerplate.
class AppRouter {
late final CounterBloc _counterBloc = CounterBloc();
Route onGenerateRoute(RouteSettings settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: _counterBloc,
child: HomePage(),
),
);
case '/counter':
return MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: _counterBloc,
child: CounterPage(),
),
);
default:
return null;
}
}
}
That's why we love flutter!
Reference: What is Null Safety in Dart?
I am using global key to handle my navigations. The main.dart, routes and NavigationService are as below. The main purpose of using the global keys is to make the navigation independent of context so that the network modules can auto log user out via the dio interceptor if the refresh token expires.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AZY APP',
navigatorKey: locator<NavigationService>().navigatorKey,
onGenerateRoute: router.generateRoute,
home: HomePageScreen())
}}
NavigationService.dart
class NavigationService {
final GlobalKey<NavigatorState> navigatorKey =
new GlobalKey<NavigatorState>();
Future<dynamic> navigateTo(String routeName, {dynamic arguments}) {
return navigatorKey.currentState.pushNamed(routeName, arguments: arguments);
}
pop(value) {
print("pop");
return navigatorKey.currentState.pop(value);
}
goBack() {
print("goback");
return navigatorKey.currentState.pop();
}
popUntil(String desiredRoute) {
return navigatorKey.currentState.popUntil((route) {
print("${route.settings.name}");
return route.settings.name == desiredRoute;
});
}
pushReplacementNamed(String route) {
print("pushReplacementNamed");
return navigatorKey.currentState.pushReplacementNamed(route);
}
}
Routes.dart
Route<dynamic> generateRoute(RouteSettings settings) {
final args = settings.arguments;
switch (settings.name) {
case routes.SplashScreenRoute:
return MaterialPageRoute(builder: (context) => SplashScreen());
case routes.LoginScreenRoute:
return MaterialPageRoute(builder: (context) => LoginScreen());
case routes.MainPageScreenRoute:
return MaterialPageRoute(builder: (context) => MainPageScreen());
case routes.HomePageScreenRoute:
return MaterialPageRoute(builder: (context) => HomePageScreen());
default:
return MaterialPageRoute(
builder: (context) => Scaffold(
body: Center(
child: Text('Error Loading Screen'),
),
),
);
}
}
All the functions in NavigationService works well except popUntil. For every route, settings.name is null so i am unable to using navigatorkey with popUntil.
Log of print("${route.settings.name}").
The problem was that I was not passing route settings to MaterialPageRoute in my router.
MaterialPageRoute(
settings: settings, builder: (context) => SplashScreen());
I want to switch between the login screen and Home screen based on bool value(user.status) from the model class below
class User extends ChangeNotifier {
int phoneNumber;
bool status = false;
notifyListeners();
}
The bool User.status value is flipped from below function
User _user = Provider.of<User>(context);
...
...
if (form.validate()) {
_user.status = true;
}
The below function has to listen to the changes in the status value from the User model and change the screen to Home().
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
User authStatus = Provider.of<User>(context);
return authStatus.status ? Home() : Auth();
}
}
I don't have any errors, all the values are updating accordingly but the Wrapper() is not being rebuilt after listening to the changes from ChangeNotifier
Here's how I do it with Provider :
routes: {
"/": (context) => MainPage(),
"/detail": (context) => UserDetailPage(),
},
builder: (context, child) {
return Consumer<UsersProvider>(
child: child,
builder: (context, provider, child) {
final value = provider.user;
if (!value.status) {
return Navigator(
onGenerateRoute: (settings) => MaterialPageRoute(
settings: settings, builder: (context) => LoginPage()),
);
}
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => UsersProvider()),
ChangeNotifierProvider(
create: (context) => InvoicesProvider()),
ChangeNotifierProvider(create: (context) => EventsProvider()),
],
child: child,
);
},
);
},
Basically use builder in main.dart and defines routes, then inside builder use Consumer were child is the initial route MainPage() so if the user already login they will go there, and if not, base on status they will redirect to LoginPage(). I hope you can understand feel free to comment