I have code that is working as desired, but I don’t understand how.
I have two Lists:
List<ProductInfo>_filter_data = [];
List<ProductInfo>masterData = [];
On app startup, build masterData from a datasheet. Within the app, filter the data based on user actions;
List<ProductInfo> results = [];
results = masterData.where((user) => type == user.selectedType ).toList(); //simplifed example
setState(() {
_filter_data = results;
});
Data is displayed via a ListView based on filter_data. Users can mark their favorites via a checkbox:
setState(() {
if (isChecked) {
_filter_data[widget.data_index].fav = true;
}
else {
_filter_data[widget.data_index].fav = false;
}
I wrote this quickly last night, and it appeared to be working. Today I’m questioning why. When users click a checkbox the _filter_data list is updated. But based on my understanding, the masterData list wouldn’t be. So as soon as a new filter is applied, and a new _filter_data is made based on the masterData, the favorite selection should be lost.
But that’s not what’s happening. Both the _filter_data and master_data lists are getting the .fav tag updated. I wrote some debug print statements that show both the _filter_data and masterData showing the fav being updated. How? Is the ProductInfo item shared between lists?
To be clear, this is the desired behavior (I want the fav data saved to masterData). I just don’t understand how it is working as written.
2
Answers
Your
List
masterData contains objects. YourList
results contains some of those objects, but does not create a copy of those objects. They are the same objects. BothList
s contain references to these same objects.Then you hand over the reference to this
List
of objects called results to _filter_data. Again, this is aList
of objects that already existed in theList
called masterData.If you manipulate an object in a
List
, while the same object is also referenced in anotherList
, then the change of this specific object is visible where ever it is referenced.1. Explanation
Hi, I have to say that you are working with mutable Lists so this is what happen:
You create an original list that fetch the data probably from a Database of a static data source:
Initialized as:
After your masterData is initialized, you filter this list and put the result of that filter on _filter_data, you just showed us how.
You mutate the objext at ‘i’ position and asked why it also mutates the masterData as well.
The answer is that the list is a list of mutable object references like in the next example:
After that, you filter the data and a possible state after of apply the filter is a list of two filtered items:
With this, you can see that the objects are being referenced and the ProductInfo2 is the same in both lists.
So if you mutate the ProductInfo2 using either masterData or _filter_data lists you will mutate the same object.
This is mutating the _filter_data[0] that could be any object at masterData[x]:
Thereby the next mutation is the equivalent of the previous one:
2. And maybe you are asking; how to avoid this?
To avoid this, I can give you two options:
Option 1: Using the map method
Create manual copies of the objects after the filter action:
This way you are creating new objects that are not being referenced at masterData object list.
Option 2: Using a package like freezed
With this library you can copy the object more easily like:
I hope this can help you.