I need to reset state of child BLOC when state of parent BLOC is changed. Let's say I have an image which is managed by ChildBloc which have a method for image scaling (so ChildBloc.state has a scale property).
When user scales image the current scale is saved in ChildBloc state and persistent. When user goes out from the page and returned back the scale must be restored.
When user changes image (let's say select new item in images list and of couuse state of ParentBloc is changed then state of ChildBloc must be set to initial and any persistence must be cleared.
Any idea how do I need to link states of those BLOCs? Is it a good idea to keep state of ChildBloc as part of state of ParentBloc?
It's hard to tell what the best state management approach is without knowing what the application does and how it works.
Anyway, in your case you have at least 2 options:
Unify the Parent and Child states. This approach would solve your problem as you have all the state in a single bloc. But it could be a really big change (again, depends on how your ChildBloc is structured)
Refer to ChildBloc inside a ParentBloc event. I guess that when the user changes image in the ParentBloc you throw an event. You could refer to che ChildBloc and throw a resetState event.
Something like: context.read<ChildBloc>().resetState(ResetStateEvent(...));. You need the BuildContext to do this, but you can pass it in the ParentBloc event.
Related
I have a navbar, change between 2 screens nested with Provider create blocs. Whenever bloc constructor called. It's call api to get data and add to the stream. So the problem here, user can spam switch between 2 screens and make the bloc dispose and init => api was called multiple times.
Class Bloc1 {
const Bloc1(){
data = await fetch() //Call api
stream1.add(data) //Then add to stream
}
}
I have tried the lock. But it does not work because when recreate, the lock is recreate too -> useless.
Class Bloc1{
var lock = false;
const Bloc1(){
if(lock == false) {
data = await fetch() //Call api
stream1.add(data) //Then add to stream
}
}
}
In my opinion, the issue you are mentioning is a kind of a border case where the user will have an aggressive behavior with the switch.
That being said, I think you should clarify a few points:
Do you really want to change the switch behavior to avoid this scenario?
Does it make sense to fetch new data every time the user switches tabs? I mean, does the data change that often? Because if the data does not change, maybe it does not makes sense to make a new request to the API at that point, and you should consider fetching this data at some other point.
I think there is no way to avoid this scenario if you instantiate/dispose your bloc every time the user switches screens (unless you save the lock or previously retrieved data outside the bloc, so next time you instantiate this bloc you can provide this value via the constructor, and this way you can avoid making the API request).
Depending on your Bloc logic, a solution could be that you instantiate the Bloc above these two screens, by doing this the Bloc will not be disposed once you switch screens and therefore it won't be instantiated again. Take into account that this approach will make the Bloc to be alive no matter how many times the user switches screens, and it is possible that this is something that you want to avoid.
I have a very specific question when reading the documentation.
After reading the BlocBuilder documentation, I then went on by reading about the BlocListener. Everything was pretty clear, until I read this:
The listener is guaranteed to only be called once for each state
change unlike the builder in BlocBuilder.
As I understand, in BlocBuilder the builder: gets called every time the bloc state changes (of course in the case in which buildWhen: is omitted and it always returns true as a default value). And in BlocListener the listener: gets called in response to state changes in the bloc.
I can't seem to understand the concept behind the quoted text. Doesn't the builder: in BlocBuilder also get called once for every change in the state of the bloc? Where's that "second" call I'm missing happening?
The builder is run as you say upon state change. But the builder function is also run when the framework deems necessary to rebuild.
The listener function is not affected by the frameworks need to rebuild.
Every time when a new state is emitted by the bloc it is compared with the previous one, and if they are DIFFERENT, the listener function is triggered.
If in you situation, you are using Equatable with only LoadedState as props, which means when two states are compared only the LoadedState are tested. In this way BLoC consumer thinks that the two states are equal and do not triggers the listener function again.
if you want to update same state just add one state before calling your updating state like this, if you want to update 'LoadedState' state again call 'LoadingState' state before that and than call 'LoadedState' state so BlocListener and BlocBuilder will listen to it
I read that setState affect application performance because it rebuilds the widget tree.
Calling setState notifies the framework that the internal state of
this object has changed in a way that might impact the user interface
in this subtree, which causes the framework to schedule a build for
this State object.
Is this an actual concern for application performance?
Yeah, it may but only if you are calling the function too many times unnecessarily.
What's the best practice?
Try calling it at the end of functionality or only when you need to
update the widget, you can also create multiple subclasses ( stateful
widget), so if you want some changes in a particular area only, then
only that widget will get updated not the entire screen.
What will happen if An event is added to the bloc being passed inside the BlocProvider.value?
Will the event gets added before or after i get to the page?
And Is Blocprovider.value an ideal way to avoid adding events to bloc in initState() method?
I'm trying to avoid initstate as I'm listening to Stream of data from firebase (this event need to be called only once).
I found a workaround for this,
Using the approach stated above will make the LoadProductFromStream event get called even before getting to /opening the StreamproductPage().
To avoid this a simple and efficient approach could be used instead
create a wrapper widget
create the body (the main widget to display results)
Below is an image attached to explain this
Wrapper widget is where the bloc will be created/initialized
and where LoadProductFromStream() event will be added to the bloc
In conclusion
This way we only add LoadFromStream() event to bloc when we get to StreamproductPage
Takeaway
BlocProvider(create:(context)=> xyzBloc()) // can automatically close bloc
while
BlocProvider.value() // doesn't close bloc automatically
(i stand to be corrected)
I get the general idea that the StatefulWidget my get rebuild very often, and even get assigned to a different State if not using key in some cases. However the State of that widget always exists in memory. I need to change some data of the State when it's not shown. Is it safe to keep the reference of that State instance for example in a singleton and change its data?
Specifically, I have a StatefulWidget(call it homapage) with PageView. Its State keeps the reference of the PageController. I want to change the controller.page when the screen is showing other tabs rather than homepage. I did this via keeping a reference of the State in a singleton. In order to do it, I need to make the State class public by deleting the _ in front of the State class name. If feels unsafe and against the Flutter design philosophy to me.
The state will be destroyed when a widget that uses that state is no longer in the widget tree. We recommend that you use GlobalKey and don't use a singleton as a reference to the State. Using InheritedWidget is also a good option.