Reputation: 399
I am creating an e-commerce app where homepage is kind of page where all fields like categories and other info is given.
here is my flow of screens ... HomeScreen -> CategoryPage -> ProductByCategory -> ProductLandingPage
I am getting error. New to Coding and learning Providers for 1st time, Not able to resolve this issue.
Error: Could not find the correct Provider above this ProductLandingPage Widget
To fix, please:
void main() {
runApp(MaterialApp(
home: MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Cart(),
)
],
child: HomeScreen(),
),
debugShowCheckedModeBanner: false,
));
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.redAccent,
title: Text('Factory2Homes'),
actions: <Widget>[
IconButton(icon: Icon(Icons.search), onPressed: () {}),
Consumer<Cart>(
builder: (_, cart, ch) => Badge(
child: ch,
value: cart.itemCount.toString(),
),
child: IconButton(
icon: Icon(
Icons.shopping_cart,
),
onPressed: () {
},
),
),
],
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(height: 500, child: CategoryPage()),
],
),
),
);
}
}
class CategoryPage extends StatefulWidget {
@override
_CategoryPageState createState() => _CategoryPageState();
}
class _CategoryPageState extends State<CategoryPage> {
@override
Widget build(BuildContext context) {
return FutureBuilder<List<AllCategory>>(
future: getCategoryList(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? ListOfCategories(
categories: snapshot.data,
)
: Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red,
));
},
);
}
}
class ListOfCategories extends StatelessWidget {
final List<AllCategory> categories;
ListOfCategories({this.categories});
@override
Widget build(BuildContext context) {
return GridView.builder(
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemCount: categories.length,
itemBuilder: (context, index) {
return InkWell(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => ProductByCategory(category: categories[index],)));
},
child: Image.network(categories[index].categoryIcon));
},
);
}
}
class ProductByCategory extends StatefulWidget {
final AllCategory category;
final CarouselSlider carouselslider;
ProductByCategory({this.category, this.carouselslider});
@override
_ProductByCategoryState createState() => _ProductByCategoryState();
}
class _ProductByCategoryState extends State<ProductByCategory> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
Consumer<Cart>(
builder: (_, cart, ch) => Badge(
child: ch,
value: cart.itemCount.toString(),
),
child: IconButton(
icon: Icon(
Icons.shopping_cart,
),
onPressed: () {
},
),
),
IconButton(icon: Icon(Icons.search), onPressed: () {}),
],
),
body: FutureBuilder<List<Product>>(
future: getCategoryByProduct(http.Client(), widget.category.id),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
if (snapshot.hasData) {
return ProductByCategoryScreen(
product: snapshot.data,
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
);
}
}
class ProductByCategoryScreen extends StatefulWidget {
final List<Product> product;
ProductByCategoryScreen({this.product});
@override
_ProductByCategoryScreenState createState() =>
_ProductByCategoryScreenState();
}
class _ProductByCategoryScreenState extends State<ProductByCategoryScreen> {
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemCount: widget.product.length,
itemBuilder: (context, index) {
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ProductLandingPage(widget.product[index])));
},
child:
Card(child: Image.network(widget.product[index].productPhoto)));
},
);
}
}
class ProductLandingPage extends StatefulWidget {
final Product product;
ProductLandingPage(this.product);
@override
_ProductLandingPageState createState() => _ProductLandingPageState();
}
class _ProductLandingPageState extends State<ProductLandingPage> {
@override
Widget build(BuildContext context) {
final cart = Provider.of<Cart>(context, listen: false);
return Scaffold(
appBar: AppBar(
actions: <Widget>[
],
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
color: Colors.green,
height: MediaQuery.of(context).size.height / 2,
child: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Image.network(widget.product.productPhoto),
),
),
Divider(
thickness: 1,
),
Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(this.widget.product.productName),
),
),
Divider(),
Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Text(
'₹' + '${this.widget.product.productSalePrice}',
style: TextStyle(
fontSize: 30, fontWeight: FontWeight.w500),
),
),
],
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Center(
child: Text(
'MRP:' + '${this.widget.product.productListPrice}'),
),
),
],
),
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Text(
'Description',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
),
],
),
Container(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(this.widget.product.productDescription),
),
),
],
),
),
bottomNavigationBar: Container(
width: MediaQuery.of(context).size.width,
height: 45.0,
child: RaisedButton(
onPressed: () {
cart.addItem(
'${widget.product.productId}',
widget.product.productListPrice,
widget.product.productName,
);
},
color: Colors.redAccent,
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.card_travel,
color: Colors.white,
),
SizedBox(
width: 4.0,
),
Text(
"ADD TO CART",
style: TextStyle(color: Colors.white),
),
],
),
),
),
));
}
}
class CartItem {
final String id;
final String title;
final int quantity;
final int price;
CartItem({
this.id,
this.title,
this.quantity,
this.price,
});
}
class Cart with ChangeNotifier {
Map<String, CartItem> _items;
Map<String, CartItem> get items {
return {..._items};
}
int get itemCount{
return _items==null ?0 :_items.length;
}
void addItem(
String productId,
int productListPrice,
String productName,
) {
if (_items.containsKey(productId)) {
_items.update(
productId,
(existingCartItem) => CartItem(
id: existingCartItem.id,
title: existingCartItem.title,
price: existingCartItem.price,
quantity: existingCartItem.quantity + 1,
));
} else {
_items.putIfAbsent(
productId,
() => CartItem(
id: DateTime.now().toString(),
title: productName,
price: productListPrice,
quantity: 1,
));
}
}
}
Upvotes: 0
Views: 735
Reputation: 188
The idea of Provider is to lift the state management above the widgets so different children can easily access its state. So it would be helpful if you moved the HTTP request from the widget tree (where it will be called every time the UI updates, so users use more bandwidth than needed) to a provider that is created above the tree. Therefore the state doesn't need to passed around from widget to widget.
Try watching this amazing talk from the flutter team to get a better understanding of how to use provider: https://youtu.be/d_m5csmrf7I
Bdw read this StackOverflow answer about why .value
isn't what you desire: How to deal with unwanted widget build?
So you should make the app like this
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => Cart(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Factory2Homes',
home: HomeScreen(),
),
);
}
}
Upvotes: 1
Reputation: 399
i got it working by changing main.dart code to below code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(value: Cart(),
child:MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Factory2Homes',
home: HomeScreen(),
),);
}
}
Upvotes: 0