I am new to Flutter and am following a course on Udemy. I have a model called Item which has final
properties as shown:
class Item {
final String id;
final String title;
final int quantity;
final double price;
Item({
required this.id,
required this.title,
required this.quantity,
required this.price,
});
}
The Item
is used by another class Cart
which stores a list of Item
s in a map and it has a removeSingleItem
method which reduces the quantity like this:
class Cart with ChangeNotifier {
Map<String, Item> _items = {};
void removeSingleItem(String productId) {
if (!_items.containsKey(productId)) {
return;
}
if (_items[productId]!.quantity > 1) {
_items.update(
productId,
(existingCartItem) => Item(
id: existingCartItem.id,
price: existingCartItem.price,
quantity: existingCartItem.quantity - 1,
title: existingCartItem.title,
));
} else {
_items.remove(productId);
}
notifyListeners();
}
As we can see that the cart is a provider.
Why do we create a new Item
using _items.update
? instead of modifying the content of the Item object directly like this after making the property non-final:
_items[productId]!.quantity -= 1;
Will this cause any problems in state management? Because in the demo application the orders screen (new Scaffold) seems to get updated properly even if we don't create an entire new Item object.
The most dangerous thing with a mutable data class is that it's possible to mutate it from every part of the code, not only the model provider.
Those are some of the aspects of making the data immutable:
That's why a bunch of classes have the copyWith
method to mutate just one property but it returns a new object instance.
So, make Item
immutable and create a copyWith
method like the following snippet:
class Item {
final String id;
final double price;
final double quantity;
final String title;
const Item({
required this.id,
required this.price,
required this.quantity,
required this.title,
});
Item copyWith({
String? id,
double? price,
double? quantity,
String? title,
}) {
return Item(
id: id ?? this.id,
price: price ?? this.price,
quantity: quantity ?? this.quantity,
title: title ?? this.title,
);
}
}
This way creating a new instance from an existing one is much easier:
_items.update(
productId,
(existingCartItem) => existingCartItem.copyWith(
quantity: existingCartItem.quantity - 1,
));