Ошибка Flutter: не удалось найти правильный поставщик ‹Cart› над этим виджетом ProductLandingPage

Я создаю приложение для электронной коммерции, где домашняя страница - это своего рода страница, на которой указаны все поля, такие как категории и другая информация.

вот мой поток экранов ... HomeScreen -> CategoryPage -> ProductByCategory -> ProductLandingPage

Я получаю сообщение об ошибке. Впервые в сфере программирования и обучения, не могу решить эту проблему.

Ошибка: не удалось найти правильный поставщик над этим виджетом ProductLandingPage

Чтобы исправить, пожалуйста:

  • Убедитесь, что поставщик является предком этого виджета ProductLandingPage
  • Предоставьте типы поставщику
  • Предоставьте типы потребителю
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,
              ));
    }
  }
}

person chetan suri    schedule 06.06.2020    source источник
comment
Сначала измените ChangeNotifierProvider.value (value: Cart (),) на ChangeNotifierProvider (create: Cart (),)   -  person camillo777    schedule 06.06.2020


Ответы (2)


Идея Provider состоит в том, чтобы поднять управление состоянием над виджетами, чтобы различные дочерние элементы могли легко получить доступ к его состоянию. Поэтому было бы полезно, если бы вы переместили HTTP-запрос из дерева виджетов (где он будет вызываться каждый раз при обновлении пользовательского интерфейса, чтобы пользователи использовали большую полосу пропускания, чем необходимо) к провайдеру, который создается над деревом. Следовательно, состояние не нужно передавать от виджета к виджету.

Посмотрите этот замечательный доклад команды разработчиков флаттера, чтобы лучше понять, как использовать провайдера: https://youtu.be/d_m5csmrf7I

Bdw прочитайте этот ответ StackOverflow о том, почему .value не то, что вы хотите: Как бороться с нежелательной сборкой виджета?

Итак, вы должны сделать приложение таким

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(),
      ),
    );
  }
}
person Gabber235    schedule 06.06.2020

Я получил его, изменив код main.dart на код ниже:

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(),
      ),);
  }
}
person chetan suri    schedule 06.06.2020