I have the following dart class which loads an object and an image. When I perform hot reload, the function findById returns an error message Bad State: No element. Upon debugging, I see that the list that I am querying on is null once I do a hot realod. I want to know why that happens and how do I fix this?
class ProductDetailScreen extends StatefulWidget {
static const routeName = '/product-detail';
@override
_ProductDetailScreenState createState() => _ProductDetailScreenState();
}
class _ProductDetailScreenState extends State<ProductDetailScreen> {
var loadedProduct;
var productId;
var _isLoading;
var _imageUrl;
var cartId;
var imagePath = '';
@override
void initState() {
super.initState();
createCartId();
}
Future<void> createCartId()async {
var id = await nanoid(10);
cartId = id;
}
Future<void> didChangeDependencies() async {
productId = ModalRoute.of(context).settings.arguments as String;
imagePath = productId;
setState(() {
_isLoading = true;
});
final myCacheManager = MyCacheManager();
await myCacheManager.cacheImage(imagePath).then((String imageUrl) {
setState(() {
_imageUrl = imageUrl;
_isLoading = false;
});
});
}
@override
Widget build(BuildContext context) {
loadedProduct = Provider.of<Products>(context,listen:false).findById(productId);
Size size = MediaQuery.of(context).size;
var userId = Provider.of<Auth>(context, listen: false).userId;
return !(_isLoading)?Scaffold(
appBar: AppBar(
actions: null,
title: Text(loadedProduct.title),
),
body:
CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child:
Column(
children: <Widget>[
Container(
height: size.height * 0.35,
width: double.infinity,
child:_imageUrl != 'No picture loaded'?
CachedNetworkImage(
imageUrl: _imageUrl,
progressIndicatorBuilder: (context, url, downloadProgress) =>
Center(child:Loading()),
errorWidget: (context, url, error) => Image.asset('assets/images/placeholder.png'),
)
:Image.asset('assets/images/placeholder.png'),
),
Expanded(
child: ItemInfo(
cartId,
loadedProduct.id,
loadedProduct.title,
loadedProduct.price,
loadedProduct.description,
loadedProduct.categoryName,
loadedProduct.isAvailable),
),
],
))]))
:Center(child:Loading());
}
}
class ItemInfo extends StatefulWidget {
ItemInfo(this.cartId,this.id,this.name,this.price,this.description,this.category,this.isAvailable);
var id;
var cartId;
var name;
var price;
var description;
var category;
var isAvailable;
@override
_ItemInfoState createState() => _ItemInfoState();
}
class _ItemInfoState extends State<ItemInfo> {
bool changePrice = false;
List<String> selectedItems;
@override
Widget build(BuildContext context) {
return
Container(
padding: EdgeInsets.all(15),
width: double.infinity,
decoration: BoxDecoration(
boxShadow: [BoxShadow(color: Colors.orange, spreadRadius: 1)],
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
),
),
child:
Column(
children: <Widget>[
TitlePriceRating(
name: widget.name,
price: widget.price,
),
],
),
);
}
}
Here's the function function findById
Product findById(String id) {
return _items.firstWhere((prod) => prod.id == id);
}
Here's the function which sets the _items list:
Future<void> fetchAndSetProducts(String title) async {
var encodedTitle = Uri.encodeComponent(title);
var url = 'https://mm-nn-default-rtdb.firebaseio.com/products.json?auth=$authToken';
try {
final response = await http.get(Uri.parse(url));
final extractedData = json.decode(response.body) as Map<String, dynamic>;
final List<Product> loadedProducts = [];
if (extractedData == null || extractedData['error'] != null) {
_items = loadedProducts;
return _items;
}
extractedData.forEach((prodId, prodData) {
loadedProducts.add(Product(
id: prodId,
title: prodData['title'],
description: prodData['description'],
price: prodData['price'],
categoryName: prodData['categoryName'],
));
});
notifyListeners();
_items = loadedProducts;
return _items;
} catch (error) {
throw (error);
}
}
This function is called in a class called ProductOverviewScreen which then calls a class called ProductGrid. ProductGrid basically contains a listviewbuilder of the products. This class then calls ProductItem which is basically a single product in the product list. ProductItem contains a button which when clicked, calls ProductDetailsScreen which is the class causing the error.