Initialize variable inside 'initState' or just below the class definition? [duplicate] - flutter

This question already has an answer here:
is there any difference between assigning value to the variable inside of initState or not in Flutter StatefulWidget?
(1 answer)
Closed 2 years ago.
I am wondering when I know the initial value to a variable in a State class in Flutter, whether I should initialize it with the variable definition or inside initState method. What is better and why?
First method:
class _SampleState extends State<Sample> {
String _foo = 'FOO';
#override
void initState() {
// Do some other stuff
super.initState();
}
...
}
Second method:
class _SampleState extends State<Sample> {
String _foo;
#override
void initState() {
_foo = 'FOO';
// Do some other stuff
super.initState();
}
...
}

What I think is you can initially define it without using the initstate(), but if you assigning any value to it then there comes the initstate where you process some things like api calls or any other and then assign the value to it.
For More details check out this link where Remi has explained :
is there any difference between assigning value to the variable inside of initState or not in Flutter StatefulWidget?

When you know the value at construction time, then i would suggest, you set it at construction time (in the constructor or as default value at the definition).
When you know the value at a specific time of the widget lifecycle, like at init, then use the respective method.

The main difference is that initState() is called at the point when widget is already added to the tree and you already have access to this.context and this.widget.
So, unless you're using BuildContext or your instance of StatefulWidget, I recommend you to proceed with String _foo = 'FOO'; in the class declaration just because it looks simpler.
Third possible option is to assign _foo in the class constructor. Again, it makes sense only if the value of the property for some reason can't be assigned along with its definition, for example if it depends on values of other class properties.

Related

Changes in Object from Second Screen is also Changing the Value in First Screen in flutter dart

A class Object passing from First Screen to the second Screen While on the second screen when the object changed its value, it's also changing the value on first screen.
Code of First Screen. (widget.templateModel is an object class that i am passing to the second screen)
Navigator.push(context,MaterialPageRoute(builder: (context) =>
EditEmojiTextTemplateScreen(templateModel: widget.templateModel,));
Code of Second Screen (On the second screen i am receiving the object and when i am changing the value of widget.templateModel it also changing the value on the first screen for a simple understandable code below i changed the value in initState while in the gif i am changing value in TextFormField)
class EditEmojiTextTemplateScreen extends StatefulWidget {
final TemplateModel templateModel;
EditEmojiTextTemplateScreen({
Key? key,
required this.templateModel,
}) : super(key: key);
#override
State<EditEmojiTextTemplateScreen> createState() =>
_EditEmojiTextTemplateScreenState();
}
class _EditEmojiTextTemplateScreenState
extends State<EditEmojiTextTemplateScreen> {
final SharedPreferences sharedPreferences = sl();
var txtNameController = TextEditingController();
var txtColorController = TextEditingController();
_EditEmojiTextTemplateScreenState();
#override
void initState() {
widget.templateModel.emoji[0].titleTwo = "kdfff"; //here i am changing the value and it also changing the value on first screen and i dont want this behavior of this object
super.initState();
}
Note: This is happening because of widget variable as mentioned in the documentation but i don't know how to prevent this behavior.
package:flutter/src/widgets/framework.dart
The current configuration.
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.
Now I see what you are trying to do.
You could initialize a NEW istance of TemplateModel in the InitState of the second screen.
Then, set the new object's properties like this (or write a cleaner method to do that):
newObject.property1 = oldObject.property1;
newObject.property2 = oldObject.property2;
...
Once the user presses the save button, change oldObject's properties again, so that the first page updates.
You might want to take a look at state management to better understand how to approach this kind of problems.
As the other answer suggests, take a look at state management solutions.
Also keep the models immutable by creating them with final fields. Then to modify, create new instances via copyWith()
Please update you code after navigation.then method
template = snapshot.data;

Avoid no_logic_in_create_state warning when saving reference to State of StatefulWidget in Flutter

Using Flutter, I display a list of elements in an app.
I have a StatefulWidget (ObjectList) that holds a list of items in its State (ObjectListState).
The state has a method (_populateList) to update the list of items.
I want the list to be updated when a method (updateList) is called on the widget.
To achieve this, I save a reference (_state) to the state in the widget. The value is set in createState. Then the method on the state can be called from the widget itself.
class ObjectList extends StatefulWidget {
const ObjectList({super.key});
static late ObjectListState _state;
#override
State<ObjectList> createState() {
_state = ObjectListState();
return _state;
}
void updateList() {
_state._populateList();
}
}
class ObjectListState extends State<ObjectList> {
List<Object>? objects;
void _populateList() {
setState(() {
// objects = API().getObjects();
});
}
// ... return ListView in build
}
The problem is that this raises a no_logic_in_create_state warning. Since I'm not "passing data to State objects" I assume this is fine, but I would still like to avoid the warning.
Is there a way to do any of these?
Saving the reference to the state without violating no_logic_in_create_state.
Accessing the state from the widget, without saving the reference.
Calling the method of the state from the outside without going through the widget.
It make no sense to put the updateList() method in the widget. You will not be able to call it anyway. Widgets are part of a widget tree, and you do not store or use a reference to them (unlike in other frameworks, such as Qt).
To update information in a widget, use a StreamBuilder widget and create the widget to be updated in the build function, passing the updated list to as a parameter to the widget.
Then, you store the list inside the widget. Possibly this may then be implemented as a stateless widget.

Why do we need to initialize late a class on run time and not directly on compile time in flutter?

I'm wondering, if we create an instance of a class, we create the instance first and mark it as late before assigning a value on the initState? Why dont we just assign a value to it at compile time directly?
//what is the difference of this
SampleClass _sample = SampleClass();
//with this?
late SampleClass _sample;
void initState(){
super.initState():
_sample = SampleClass();
}
When SampleClass depends on context, the initialization must happen in initState which is when the widget is inserted into the tree, otherwise no need to delay the initialization.

What is the difference between the following var initialization positions in a StatefulWidget?

I was wondering about where to declare and initialize variables in the case of a StatefulWidget. There seem to be a couple of ways to do it, but are there differences, any guidelines, or best practice approaches for it?
I created the below sample, but can not find any differences except that when performing a hot reload, variable i loses its value and is back to zero again.
I read this, but it contains so many contradicting comments.
class Sample extends StatefulWidget {
int i=0;
late Object object1 = Get.put(Object());
#override
_SampleState createState() => _SampleState();
}
class _SampleState extends State<Sample> {
int j = 0;
late Object object2;
#override
void initState() {
i=5;
j=5;
object1.param="value123";
object2=Get.put(Object());
object2.param="value123";
}
#override
Widget build(BuildContext context) {
}
}
First, if you run your app on the emulator you can indeed find no differences. But, that observation is huge misleading!
Variables declared whether initialized or not inside the Widget class are not persisted in the case of widget recreation. StatefulWidgets (and all Widget subclasses) are thrown away and rebuilt whenever configuration changes. Luckily, you can force performing Widget recreation by performing a hot reload on the widget while you are testing your app. to ensure proper behavior.
If you want to declare variables that should persist (State data), make sure to put them inside the State class as int j in the above code example.
Use initState() for variables that you cannot initialize within the declaration statement.
Why then object1 retain its data?
Simply, because GetX will not recreate a new instance of Object if one already exists. It will return back the old instance every time the Widget is rebuilt. That's why no difference is perceived in the case of object1 and object2 places of declaration.
At the time of writing this answer, you have to manually call Get.delete<>() in order to dispose a controller if you are not using bindings.

Flutter: Difference in initializing variables in a Class

Currently I'm assigning all variables through initState however I'm seeing that there is no need to assign the variables through initState as I can just assign the variable with a value directly. What is the order of these assignments and how are they different? Why and when would you choose one instead of the other?
class Person {
String name = "John";
#override
void initState(){
....
....
}
}
vs
class Person {
String name;
#override
void initState(){
name = "John";
}
}
In your first example, the assignment takes place during construction. You might want to use this form if name is final.
In the second example, the assignment takes place when initState is called, which could be zero, one or more times. Presumably you are referring to the initState of State<T> which the framework calls once, after construction.
The difference is that the first variable cannot be assigned dynamic content to, like AnimationController(vsync: this), you have to do that in initState.
I would guess initState assigning decreases performance a little bit, because you have more options.
I'd recommend using the regular assigning of variables whenever it's possible, and using initState() only when you have to.