Closed realtebo closed 5 years ago
@realtebo you can achieve that by using BlocProvider
to access the CounterBloc
using the BuildContext
.
class ThirdPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);
return BlocBuilder(
bloc: _counterBloc,
builder: (BuildContext context, int count) {
return Text('$count');
}
}
}
Does that help?
I was following this approach by myself, but I get
I/flutter ( 6351): The following assertion was thrown building OtherPage(dirty): I/flutter ( 6351): BlocProvider.of() called with a context that does not contain a Bloc of type CounterBloc. I/flutter ( 6351): No ancestor could be found starting from the context that was passed to I/flutter ( 6351): BlocProvider.of
(). This can happen if the context you use comes from a widget above the I/flutter ( 6351): BlocProvider. I/flutter ( 6351): The context used was: I/flutter ( 6351): OtherPage(dirty)
This my target page code
import '../counter_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class OtherPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);
return MaterialApp(
title: 'Other Page',
home: BlocProvider<CounterBloc>(
bloc: _counterBloc,
child: Center(
child: Text(
_counterBloc.currentState.toString(),
style: TextStyle(fontSize: 24.0),
),
),
),
);
}
}
If you want your Bloc to be accessible globally (across different routes) you need to make sure that the BlocProvider
is an ancestor of the MaterialApp
widget.
class App extends StatefulWidget {
@override
State<StatefulWidget> createState() => _AppState();
}
class _AppState extends State<App> {
final CounterBloc _counterBloc = CounterBloc();
@override
Widget build(BuildContext context) {
return BlocProvider<CounterBloc>(
bloc: _counterBloc,
child: MaterialApp(
title: 'Flutter Demo',
home: CounterPage(),
),
);
}
@override
void dispose() {
_counterBloc.dispose();
super.dispose();
}
}
Also, there's no need to have multiple BlocProviders
for the same bloc. A BlocProvider
makes the bloc available to all widgets in it's subtree.
I'm doing this. [thanks for fast reply]
void main() {
BlocSupervisor().delegate = SimpleBlocDelegate();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
final CounterBloc _counterBloc = CounterBloc();
@override
Widget build(BuildContext context) {
return BlocProvider<CounterBloc>(
bloc: _counterBloc,
child: MaterialApp(
title: 'Flutter Demo',
home: CounterPage(),
),
);
}
@override
void dispose() {
_counterBloc.dispose();
super.dispose();
}
}
import 'package:bloc_youtube_video/counter_bloc.dart';
import 'package:bloc_youtube_video/counter_event.dart';
import 'package:bloc_youtube_video/page/other_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: BlocBuilder<CounterEvent, int>(
bloc: _counterBloc,
builder: (BuildContext context, int count) {
return Center(
child: Text(
'$count',
style: TextStyle(fontSize: 24.0),
),
);
},
),
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
_counterBloc.dispatch(Increment());
},
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: Icon(Icons.remove),
onPressed: () {
_counterBloc.dispatch(Decrement());
},
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: Icon(Icons.pageview),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return OtherPage();
},
),
);
},
),
),
],
),
);
}
}
import '../counter_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class OtherPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Other page')),
body: Center(
child: Text(
_counterBloc.currentState.toString(),
style: TextStyle(fontSize: 24.0),
),
),
);
}
}
When I navigate to other page, screen became black and got exception
I/flutter ( 6694): ══╡ EXCEPTION CAUGHT BY SCHEDULER LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 6694): The following assertion was thrown during a scheduler callback:
I/flutter ( 6694): There are multiple heroes that share the same tag within a subtree.
I/flutter ( 6694): Within each subtree for which heroes are to be animated (typically a PageRoute subtree), each Hero
I/flutter ( 6694): must have a unique non-null tag.
I/flutter ( 6694): In this case, multiple heroes had the following tag: <default FloatingActionButton tag>
I/flutter ( 6694): Here is the subtree for one of the offending heroes:
I/flutter ( 6694): # Hero(tag: <default FloatingActionButton tag>, state: _HeroState#0d7ed)
And is not understandable
You need to provide a heroTag
for each of the FloatingActionButton
widgets.
This has nothing to do with the Bloc library and is part of how Flutter works. You can't have more than one FloatingActionButton
per page without uniquely identifying them using a heroTag
.
Change counter_page.dart
to:
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: BlocBuilder<CounterEvent, int>(
bloc: _counterBloc,
builder: (BuildContext context, int count) {
return Center(
child: Text(
'$count',
style: TextStyle(fontSize: 24.0),
),
);
},
),
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
heroTag: 0,
child: Icon(Icons.add),
onPressed: () {
_counterBloc.dispatch(CounterEvent.increment);
},
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
heroTag: 1,
child: Icon(Icons.remove),
onPressed: () {
_counterBloc.dispatch(CounterEvent.decrement);
},
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
heroTag: 2,
child: Icon(Icons.pageview),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute<OtherPage>(
builder: (BuildContext context) {
return OtherPage();
},
),
);
},
),
),
],
),
);
}
}
Oh yes, now it works. A final question, I hope:
In the other page I need block builder only If I must dispatch events, right?
So I can simply have
class OtherPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Other page')),
body: Center(
child: Text(
_counterBloc.currentState.toString(),
style: TextStyle(fontSize: 24.0),
),
),
);
}
}
Right?
If this is almost all, your plugin is the most flexible at the minor code rows cost.
EDIT: I just discovered: https://felangel.github.io/bloc/#/coreconcepts
I Promise I read it very well. !
You only need BlocBuilder
if you want to be able to render different widgets in response to different states.
Think of BlocBuilder
like StreamBuilder
; whenever the Bloc's state changes, the builder function will be called with the new state (in this case the integer) and you can render whatever you want.
You don't need BlocBuilder
to dispatch events; in order to dispatch you just need to have access to the bloc itself and call dispatch (_counterBloc.dispatch(CounterEvent.increment)
).
In this case you can just print currentState
but I would recommend using BlocBuilder
for most cases instead of directly accessing the bloc's state because it makes the UI code a bit cleaner (especially in more complex examples).
Haha yeah definitely check out the documentation 👍 I am still making lots of updates to the documentation so it should have even more details and examples over the next few weeks.
Did I answer all of your questions?
Closing this for now. Feel free to comment if you have any more questions!
Sorry, I'm here again. I'm playing with your plugins !
I understand that I can have a BlockProvider as ancestor of MaterialApp, so I can share the bloc between pages without loosing states.
My question now is how to use a bloc provider wth 2 blocs, should I nest it?
Could it be a good solution ? https://medium.com/@danaya/multiple-blocs-in-flutter-and-how-to-communicate-between-them-e441282dc62a
Combine multiple blocs? Like in react, combining reducers, where it allows me to splice state but with ease of handling.
@realtebo you can do either one. Nesting BlocProviders
is perfectly fine and if you want for convenience you can combine Blocs. I would slightly advise against combining blocs because it is less flexible but it's totally up to you.
@felangel Hello again :D.
I have some GlobalBlocs
above MaterialApp
, and I can access to this bloc in any route.
Then in a nested Route
I created a BlocProvider
, And I want to use in a Pages that this Screen Push.
But I have the error BlocProvider.of() called with a context that does not contain a Bloc of type ...
.
I read this:
If you want your Bloc to be accessible globally (across different routes) you need to make sure that the
BlocProvider
is an ancestor of theMaterialApp
widget.
So If my bloc need to be access, when push via Navigator, Is necessary to convert this Bloc
a GlobalBloc
?
I don't like this idea because is a NestedBloc
so i don't like to see at the top haha, and also a have a lot of Blocs
like this, and the MaterialApp will be `crazy" with a lot of a lot of blocs above...
How can I solve this?
Thanks
Hey 👋
You can just pass the Blocs via constructor in that case. Let me know if that helps!
Yes, thanks.
but I use pushNamed
and I pass the bloc like argument, but i don't know if this pass a reference or a copy :(
Navigator.of(context).pushNamed(
'SomeRouteName',
arguments: _someBloc);
and then in the pushed page
_someBloc = ModalRoute.of(context).settings.arguments;
Primitives are passed by value and objects are passed by reference. 👍
Hey 👋
You can just pass the Blocs via constructor in that case. Let me know if that helps!
I don't think it's a good solution, but i not have a better one. 😃
@yang-f I’ll update the docs later today with more information on that topic. You have 3 options though:
Imo it’s not a big deal to pass the bloc via constructor into the new page and then provide it again but like I said, I’ll add a new recipe for how to pass a bloc throughout the widget tree later today 👍
@yang-f I’ll update the docs later today with more information on that topic. You have 3 options though:
- wrap your MaterialApp with a BlocProvider for global access
- use named routes and setup the BlocProvider to be scoped for the named route
- pass the bloc via constructor into the new page and then use BlocProvider to make it available in the remaining subtree
- use your another DI library to provide the blocs
Imo it’s not a big deal to pass the bloc via constructor into the new page and then provide it again but like I said, I’ll add a new recipe for how to pass a bloc throughout the widget tree later today 👍
Now we suppose have 3 pages: A,B,C(all they depend anyBloc) and A hold a anyBloc instance. page A -> page B(anyBloc) -> page C(anyBloc form B); then we nav back form C -> B(anyBloc from C)? the lifecycle‘s complexity of bloc will grow exponentially。
@felangel : thanks for creating this really useful library/framework, which I'm just getting my head around. One question: is it better to have your blocs defined at MaterialApp level then use BlocProvider.of<MyBloc>(context);
or are there advantages or disadvantages to passing blocs to widgets via the constructor?
Are there any performance considerations?
@yang-f I’ll update the docs later today with more information on that topic. You have 3 options though:
- wrap your MaterialApp with a BlocProvider for global access
- use named routes and setup the BlocProvider to be scoped for the named route
- pass the bloc via constructor into the new page and then use BlocProvider to make it available in the remaining subtree
- use your another DI library to provide the blocs
Imo it’s not a big deal to pass the bloc via constructor into the new page and then provide it again but like I said, I’ll add a new recipe for how to pass a bloc throughout the widget tree later today 👍
@felangel , I am using Bloc pattern and named routes in my project.
I am also facing problem about access bloc across routes. I read the recipe about bloc accesshttps://felangel.github.io/bloc/#/recipesflutterblocaccess?id=route-access, but I still have no idea on how to use route access with named routes.
Could you please give more explain on "use named routes and setup the BlocProvider to be scoped for the named route"? It will be great if you can also give a code example.
Here is my code about named route:
"pageA": (context) => BlocProvider.value( value: BlocProvider.of<BlocA>(context), child: new PageA(), ),
when run it, it gives an error that "BlocProvider.of
@luandedeng I'll update the recipe sometime tomorrow with a section on named routes. Thanks for bringing that up 👍
Hello,
I'm stuck with something, still learning dart/flutter.
How would You use 2+ blocs, INSIDE of 1 bloc?
e.g in Your todos app, filtered_todos_bloc.dart:
class FilteredTodosBloc extends Bloc<FilteredTodosEvent, FilteredTodosState> {
final TodosBloc _todosBloc;
StreamSubscription _todosSubscription;
FilteredTodosBloc({@required TodosBloc todosBloc})
: assert(todosBloc != null),
_todosBloc = todosBloc {
_todosSubscription = todosBloc.listen((state) {
if (state is TodosLoaded) {
add(UpdateTodos((todosBloc.state as TodosLoaded).todos));
}
});
}
@override
FilteredTodosState get initialState {
final currentState = _todosBloc.state;
return currentState is TodosLoaded
? FilteredTodosLoaded(currentState.todos, VisibilityFilter.all)
: FilteredTodosLoading();
}
}
I was thinking about something like this:
class FilteredTodosBloc extends Bloc<FilteredTodosEvent, FilteredTodosState> {
final TodosBloc _todosBloc;
StreamSubscription _todosSubscription;
final AnotherBloc _anotherBloc;
StreamSubscription _anotherSubscription;
FilteredTodosBloc({@required TodosBloc todosBloc, @required AnotherBloc anotherBloc})
: assert(todosBloc != null, anotherBloc != null),
_todosBloc = todosBloc, _anotherBloc = anotherBloc {
_todosSubscription = todosBloc.listen((state) {
if (state is TodosLoaded) {
//add(UpdateTodos((todosBloc.state as TodosLoaded).todos));
_anotherSubscription = _anotherBloc.listen((state) {
if (state is AnotherStateLoaded) {
doSomething()
}
});
}
});
}
}
But I feel that it is just bad practice, and wouldn't work as expected.
To be specific, in my database (firestore) let's say I have 3 tables:
On home screen I wan't to show all cars for user, so logically I need to fetch all 3 tables, but 'user-car' table needs 'users' and 'cars' first, so I could provide any data from those tables, based on data from 'user-car' table.
I know I could simply put list of car id's inside user table (same hierarchy as name, email, etc), but I like the idea of decoupling everything I can. I have bad history with older firebase database, because I had to restructure whole database/backend when app grew in production :)
How would You do it?
Thanks in advance.
@luandedeng I'll update the recipe sometime tomorrow with a section on named routes. Thanks for bringing that up 👍
Lets say i have several blocs defined above my materialApp. now when i use them in different pages and use navigator.of(context), they work fine. but how can i clear all data of those blocs when i dispose a specific page and make user enter the data once more? i mean since i defined them above materialApp, i cant dispose them. the other option here is not define them above materialApp, but then i can not use navigator.of(context) to route a new page and use blocProvider there and retrieve bloc's data (dose not have the same context).
i am really disappointed with bloc. help me pls. thanks in advance.
Hi @barzansaeedpour 👋 You should only ever provide a bloc to the subtree that needs it. If a bloc is only needed for a certain page or pages, then you should not provide it above MaterialApp. Hope that helps.
Hi @barzansaeedpour 👋 You should only ever provide a bloc to the subtree that needs it. If a bloc is only needed for a certain page or pages, then you should not provide it above MaterialApp. Hope that helps.
thanks for quick answer. Is there any advanced example of using several bloc and exchange data between them? how can i use a blocs data in another bloc?
Hi @barzansaeedpour 👋 You should only ever provide a bloc to the subtree that needs it. If a bloc is only needed for a certain page or pages, then you should not provide it above MaterialApp. Hope that helps.
Is there any example of not provide blocProvider above MaterialApp and use one bloc for several pages?
@barzansaeedpour check out the bloc access recipe.
Hi @barzansaeedpour 👋 You should only ever provide a bloc to the subtree that needs it. If a bloc is only needed for a certain page or pages, then you should not provide it above MaterialApp. Hope that helps.
Is there any example of not provide blocProvider above MaterialApp and use one bloc for several pages?
I don't know a good solution for scoped bloc in my app so far. In my practice, BLOC framework is easy to use in single page; for global usage, it' s also OK. But I don't find any good solution to share a BLOC in different pages with BlocProvider. BlocProvider shares bloc only in subtree. But when we navigate to another page from origin page, the another page is not in subtree of origin page. In this case, BlocProvider doesn't work. Is it correct? @felangel
@luandedeng please refer to the recipe linked above https://github.com/felangel/bloc/issues/74#issuecomment-572043525. It covers how to pass an existing bloc to a new route.
@felangel , in our project we are using use named routes and your suggestion, is:
Hi @felangel
https://github.com/felangel/bloc/issues/74#issuecomment-516684320
I can't find this recipe. Could I have link? Or could you answer, why my example do not working?
class Router {
static const words = '/';
static const wordNew = '/word_new';
static Route<dynamic> routerFactory(RouteSettings settings) {
switch (settings.name) {
case words:
return makeWordsRoute();
case wordNew:
return makeWordsNewRouter();
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
body: Center(child: Text('No route defined for ${settings.name}')),
),
);
}
}
static MaterialPageRoute makeWordsRoute() =>
MaterialPageRoute(builder: (context) {
return BlocProvider(
create: (context) => WordsBloc(),
child: WordsScreen(),
);
});
static MaterialPageRoute makeWordsNewRouter() =>
MaterialPageRoute(builder: (context) {
return BlocProvider.value(
value: BlocProvider.of<WordsBloc>(context), // block not fount in this context
child: WordNew(),
);
});
}
@JonFir the reason yours is failing is because MaterialPageRoute's
builder callback gives you a new BuildContext
that is detached from the previous one. Instead, you should inject the existing BuildContext
into the makeWordsNewRouter
like:
static MaterialPageRoute makeWordsNewRouter(BuildContext context) =>
MaterialPageRoute(builder: (_) {
return BlocProvider.value(
value: BlocProvider.of<WordsBloc>(context), // use the injected context
child: WordNew(),
);
});
@felangel Following the topic on this question, and, after reading you last comment to JonFir, I was wondering, once we push to the new route, how do we get the same instance of the bloc in this new route??
I am doing like this:
my main.dart:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider<StatusBloc>(
create: (context) => StatusBloc(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: HomeRoute(),
),
);
}
}
in my home_route.dart I have a method to go to a new route like this:
void _pushToDetails() async {
final result = await Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: BlocProvider.of<StatusBloc>(context),
child: DetailsRoute(),
),
),
);
print("---------------------> Result is $result");
}
Not sure if I am getting the StatusBloc correctly in my DetailsRoute(), I do like this:
class DetailsRoute extends StatelessWidget {
DetailsRoute();
StatusBloc statusBloc;
@override
Widget build(BuildContext context) {
statusBloc = BlocProvider.of<StatusBloc>(context)..add(DetailsListEvent());
return Scaffold(...........)
@andreddie81 yup, the snippets you provided will result in the same bloc instance because you're using BlocProvider.value
and performing a lookup for the existing bloc instance.
A minor comment about the last snippet: you shouldn't define non-final variables in a StatelessWidget
.
class DetailsRoute extends StatelessWidget {
DetailsRoute();
@override
Widget build(BuildContext context) {
final statusBloc = BlocProvider.of<StatusBloc>(context)..add(DetailsListEvent());
return Scaffold(...........)
Hope that helps 👍
@yang-f I’ll update the docs later today with more information on that topic. You have 3 options though:
- wrap your MaterialApp with a BlocProvider for global access
- use named routes and setup the BlocProvider to be scoped for the named route
- pass the bloc via constructor into the new page and then use BlocProvider to make it available in the remaining subtree
- use your another DI library to provide the blocs
Imo it’s not a big deal to pass the bloc via constructor into the new page and then provide it again but like I said, I’ll add a new recipe for how to pass a bloc throughout the widget tree later today 👍
For those who dislikes wrapping the material app widget, or using named routes, go and try using a DI library and then just use BlocProvider.value
wherever you want to provide the bloc, I think this is the best option in terms of clean code.
Is it a better idea to create Singleton of Bloc object in DI call wherever we need? @ricpar11
@karanianandkumar I would recommend using BlocProvider to provide the bloc to the part of the widget tree that needs it.
I have an app, which has 3 pages that communicate with each other. I have wrapped the first widget with MultiBlocProvider
I have also wrapped the first widget with BlocConsumer and it works fine.
In my second screen details.dart
, I have wrapped it using a MultiBlocListener
as your Counter and Random example
When I move to this page using Navigator.push( ... )
from my first page, I get the following error
None of the above solutions worked. Please help me out
I was following this approach by myself, but I get
I/flutter ( 6351): The following assertion was thrown building OtherPage(dirty): I/flutter ( 6351): BlocProvider.of() called with a context that does not contain a Bloc of type CounterBloc. I/flutter ( 6351): No ancestor could be found starting from the context that was passed to I/flutter ( 6351): BlocProvider.of(). This can happen if the context you use comes from a widget above the I/flutter ( 6351): BlocProvider. I/flutter ( 6351): The context used was: I/flutter ( 6351): OtherPage(dirty)
This my target page code import '../counter_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class OtherPage extends StatelessWidget { @override Widget build(BuildContext context) { final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context); return MaterialApp( title: 'Other Page', home: BlocProvider<CounterBloc>( bloc: _counterBloc, child: Center( child: Text( _counterBloc.currentState.toString(), style: TextStyle(fontSize: 24.0), ), ), ), ); } }
The named parameter 'bloc' isn't defined. Try correcting the name to an existing named parameter's name, or defining a named parameter with the name 'bloc'.
I was following this approach by myself, but I get
I/flutter ( 6351): The following assertion was thrown building OtherPage(dirty): I/flutter ( 6351): BlocProvider.of() called with a context that does not contain a Bloc of type CounterBloc. I/flutter ( 6351): No ancestor could be found starting from the context that was passed to I/flutter ( 6351): BlocProvider.of(). This can happen if the context you use comes from a widget above the I/flutter ( 6351): BlocProvider. I/flutter ( 6351): The context used was: I/flutter ( 6351): OtherPage(dirty)
This my target page code import '../counter_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class OtherPage extends StatelessWidget { @override Widget build(BuildContext context) { final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context); return MaterialApp( title: 'Other Page', home: BlocProvider<CounterBloc>( bloc: _counterBloc, child: Center( child: Text( _counterBloc.currentState.toString(), style: TextStyle(fontSize: 24.0), ), ), ), ); } }
The named parameter 'bloc' isn't defined. Try correcting the name to an existing named parameter's name, or defining a named parameter with the name 'bloc'.
It means your context is missing the bloc that you are trying to access
You should pass an instance of CounterBloc
either using
BlocProvider(
create: (context) => CounterBloc(...),
child: ... )
or, if you already have an existing instance of CounterBloc
, you can pass using
BlocProvider.value(
value: BlocProvider.of<CounterBloc>(context),
child: ... )
If you are using Navigator
, you can follow the navigation reciepe https://bloclibrary.dev/#/recipesflutternavigation
I have problem in changing value between pages. Lets say, 1) Page 1 have counter. I counted to 3 and go to Page 2. 2) In page2, I can access the value 3 cuz I used the global bloc as mentions above. So, I multiply 3 with 2. Then the value in bloc state become 6. My question is In bloc state it changed to 6. But not refresh in page one's Bloc builder. Why?
I hope you are creating a new instance of global bloc on your second page. You need to use the existing global bloc that is referenced in your Page 1.
I recommend people switch from Provider to Riverpod (also by Remi) as it solves all these problems
Yes, thanks. but I use
pushNamed
and I pass the bloc like argument, but i don't know if this pass a reference or a copy :(Navigator.of(context).pushNamed( 'SomeRouteName', arguments: _someBloc);
and then in the pushed page
_someBloc = ModalRoute.of(context).settings.arguments;
@basketball-ico Thanks this is a doub I had if it would work since I need to fire an event of the bloc of the page from which it is navigated but it is named navigation. Now I know that I can pass the bloc as a navigation argument, it is not the cleanest but at least between two screens it works.
@felangel extending this discussion a little bit further, is there a way to use blocs with auto_route
package?
Also, is there a way to lazy instantiate blocs with Generated Routes? I found a solution but maybe it would make a lot of boilerplate.
Thanks
found this thread from auto_route
to be very useful. https://github.com/Milad-Akarie/auto_route_library/issues/632
what are you thoughts about using a singleton class for a bloc. That way I can put a blocprovider down a tree where I need it and not allocate the memory to that stream for the life of the application.
Hi @felangel! would you be kind to tell me an easy way of migrating from getX to Flutter_bloc? something like a comparison in between them? for example, getX has "this" while in bloc, instead of "this" we use "that". so that migration might become understandable. Thank you in advance.
hi @felangel i have a problem with navigator I have 3 page: A, B, C I used 1 bloc for all 3 pages from page A -B, i used navigator.push with blocprovider.value : Worked ok from page B-C, i used navigator.pushReplacement with blocprovider.value : not work. on page C : it said that can't find context of bloc. I think the problem was because of pushReplacement. It replace page B with page C -> So it can't find the bloc with context. How can i solve this ? Thanks :))
Navigator.pushReplacement(context,
MaterialPageRoute(
builder: (_) => BlocProvider.value(
value: context.read
Let's extended counter example, where all is working well.
Imagine I add a thir fab action that uses navigator.pushReplacement to navigate a different page.
The destination page needs to see counter value.
How to?