Flutter : Variables Reset to Default Value when Navigate to another Screen - flutter

I have a problem that some variables in screen reset back to initiated value when I navigate to another screen.
Is there a way to save these variables values even if I go to another screen?

I would recommend to check Flutter official documentation - btw they're great!
Adding Interactivity to your app:
https://flutter.dev/docs/development/ui/interactive
Usage of SetState for controlling state of your app:
https://api.flutter.dev/flutter/widgets/State/setState.html
...and some deep dive into State Management in Flutter:
https://flutter.dev/docs/development/data-and-backend/state-mgmt

To be able to properly save the variables I'ld suggest you to look up for a State Management Architecture for your app. It'll be a lot helpful in long run too.
I'ld personally suggest ProviderModel. If you havent used that before it isnt much difficult to understand.
THE BELOW MENTIONED WAY IS NOT THE RIGHT WAY, AS I SAID ABOVE TO DO IT PROPERLY USE A STATE MANAGEMENT ARCHITECTURE
BUT if in some case you dont want to do that.
You can make a class object with the member variables as the variables that you are using inside the Widget.
class CounterModel{
int counter;
CounterModel(){
counter = 0;
}
}
and onDispose inside widget you can save a copy of that class object globally.
Declare a global class object like this
CounterModel model;
and populate it on dispose.
onDispose(){
model = new CounterModel();
model.counter = <currentCounter>;
super.dispose();
}
now whenever you build the widget u can use this global object to access all it values no matter what page you are on.
BUT AGAIN YOU SHOULD NEVER DO THIS

Related

Flutter : Can't access data passed from another screen

I'm trying to build 2 screens one contains a list of products and the second has product details, I'm using Firebase to store data and so I fetch the data from Firestore in the first screen and it all works perfectly.
However, in the second screen, I pass product data correctly using Navigator but I cannot use that data in my UI.
Here is the code for my second screen:
As you can see I cannot use the name variable in my widget tree, I've seen videos on youtube and I found that some people use state management to solve this problem, but for my case I just want to pass data and display it.
The way you've passed the data is correct but the way you've accessed the data isn't.
Whenever you try to access the variables of a Class in its state, you do that using widget. So, to access the name or other variables, just do as follows:
widget.name
Additionally, if the only purpose is to pass and display the data, then, there's no need of a StatefulWidget, use a StatelessWidget instead.
A [State] object's configuration is the corresponding [StatefulWidget] instance. This property is initialized by the framework before calling [initState]. If the parent updates this location in the tree to a new widget with the same [runtimeType] and [Widget.key] as the current configuration, the framework will update this property to refer to the new widget and then call [didUpdateWidget], passing the old configuration as an argument.
For that you can use widget.key, this will work fine for you.

What is GetX Controller?

I am new with getX and I don't understand what is the purpose of GetX Controller. Based on my understanding, It basically hold variables and this is where everything changes inside the state. Can someone explain further
Rather than holding variables for state change, it provides observability. It allows declaring a variable as observable, which is by using .obs and the whole class elements can be under control or operatable. To make it work you should initialize it by using Get.put or the LazyPut method.
For more, refer this video.

What is the best form to pass data between screen with GetX?

I am new on Flutter, and I am using GetX.
I want to do a Stepper for registering, and I want to pass one object between 4 screens and fill some data on each screen.
What is the best method to do that? I was thinking to put a UserModel on a controller and pass it between screens.
Thank you so much.
Generally you don't need to manually pass around data to different pages when using most state management solutions. You store the relevant data in a single instance of the object that you access from anywhere.
class StepController extends GetxController {
// any data in this class is accessible from anywhere and doesn't
// need to be manually passed to any pages
}
Use the variables you create in the GetX class for the Steps and then from anywhere in the app you find the controller with
final controller = Get.find<StepController>();
Just make sure you initialize once it at some point with
Get.put(StepController());
I haven't use GetX but MobX(+provider). In your case, I think dependency injection is best way to share store between screens, you can consume the stores everywhere, so you dont need to pass data to other screen.

Is it safe to keep a reference of a state in Flutter?

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.

Provider - Selector rebuild when scrolling

I am using the Selector widget as shown below
Nothing wrong with it's build method, only call it when the value changes.
But when I use Devtools or android studio to track widget rebuild it's showing that the Selector it self rebuild when I am scrolling whether in a list or any other widget that support scrolling.
Yes the Selector didn't call the build method until the value changes but is this normal ?
Using Devtools:
As you can see the others (2) Selectors doesn't have to be triggers but yet they are.
sorry for my bad English, I can explain in another way in the comment section if you didn't understand me and thanks in advance.
edit:
I guess I know why the selector is rebuilding it's self, because I am using the provider class as listener to scroll controller direction with changenotifier.
here the code
in provider class:
bool isHideHomeScreenTabBar = false;
void hideShowTabBar(ScrollDirection scrollDirection) {
isHideHomeScreenTabBar = scrollDirection == ScrollDirection.reverse;
notifyListeners();
}
in my Home screen:
_scrollController.addListener(() {
Provider.of<AppProvider>(context, listen: false).hideShowTabBar(
_scrollController.position.userScrollDirection);
});
So basically the provider trigger changenotifier with every scroll I do and the selector get notified and rebuild it's self but if the value didn't change the selector won't trigger the build method (so it works fine for the child and the widget in the build method of the selector).
But even so is this normal ? and why, The other selectors aren't even listening to the scroll direction.
Anyway I found an alternative way to do this (with an animation controller) but it would be nice if someone could explain what is happening here, it's important for me at least because I might use another state management.
I know what was happing.
I am using 1 class for the provider that contains all the values I need with many methods using notifyListeners, however I thought it's ok to use 1 provider class if I use Selector for every value I had so anything that need rebuild will only rebuild when it's need it.
The problem with this approach is that with every notifyListeners call every selector got notified and rebuild it self (in my case when any scrolling detected) but the selector doesn't call the builder if the value not changed.
The fix is to make some condition that check the old value and the new value before calling notifyListeners, that works prefect in my case, this decrease the rebuilding happing when I scroll to only 1 as it's intended to be, however the other selectors in the same class also rebuild (I guess because they are all in the same class so every notifyListeners call effect them).
At the end if you end up with similar issue it is better to use ProxyProvider or any way that let you use multiple providres, beside the benefit of a better project architecture and disposing it is way better to have more control over the state.
Thanks to RĂ©mi Rousselet Riverpod it's way better than ProxyProvider and I am using it and it's awesome so consider Riverpod if you want to use ProxyProvider.