【问题标题】:BlocProvider bug in Flutter and how to fix itFlutter 中的 BlocProvider 错误以及如何修复它
【发布时间】:2020-11-15 18:36:12
【问题描述】:

所以我在 BlocProvider 方面遇到了一些问题。这是我遇到的问题:

编辑:在主页上添加了 DrinkBloc 并更改了 sn-p:

完整代码

   @override
  Widget build(BuildContext context) {
    print("Building entire food list scaffold");
    return Scaffold(
      appBar: AppBar(title: Text("FoodList")),
      //THE BLOCPROVIDER 
      body: BlocProvider(
      //the issue might be that it is DrinkBloc(), but I have 2 separate tables, one after another
        create: (BuildContext context) => DrinkBloc(),
        child: Column(children: [
          Row(
            children: [
              Text('Drinks'),
              Divider(),
              IconButton(
                  icon: Icon(Icons.add),
                  onPressed: () => Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (BuildContext context) => DrinkForm())))
            ],
          ),
          Expanded(
            child: Container(
              child: BlocConsumer<DrinkBloc, List<Drink>>(
                builder: (context, drinkList) {
                  return ListView.separated(
                    itemBuilder: (BuildContext context, int index) {
                      print("drinkList: $drinkList");

                      Drink drink = drinkList[index];
                      return ListTile(
                          title: Text("${drink.name}",
                              style: TextStyle(fontSize: 30)),
                          onTap: () => showDrinkDialog(context, drink, index));
                    },
                    itemCount: drinkList.length,
                    separatorBuilder: (BuildContext context, int index) =>
                        Divider(color: Colors.black),
                  );
                },
                listener: (BuildContext context, drinkList) {},
              ),
            ),
          ),
          Row(
            children: [
              Text('Foods'),
              Divider(),
              IconButton(
                  icon: Icon(Icons.add),
                  onPressed: () => Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (BuildContext context) => FoodForm())))
            ],
          ),
          Expanded(
            child: Container(
              child: BlocConsumer<FoodBloc, List<Food>>(
                builder: (context, foodList) {
                  return ListView.separated(
                    itemBuilder: (BuildContext context, int index) {
                      print("foodList: $foodList");

                      Food food = foodList[index];
                      return ListTile(
                          title:
                              Text(food.name, style: TextStyle(fontSize: 30)),
                          subtitle: Text(
                            "Calories: ${food.calories}\nVegan: ${food.isVegan}",
                            style: TextStyle(fontSize: 20),
                          ),
                          onTap: () => showFoodDialog(context, food, index));
                    },
                    itemCount: foodList.length,
                    separatorBuilder: (BuildContext context, int index) =>
                        Divider(color: Colors.black),
                  );
                },
                listener: (BuildContext context, foodList) {},
              ),
            ),
          ),
        ]),
      ),



  class DrinkBloc extends Bloc<DrinkEvent, List<Drink>> {
  @override
  List<Drink> get initialState => List<Drink>();

  @override
  Stream<List<Drink>> mapEventToState(DrinkEvent event) async* {
    if (event is SetDrinks) {
      yield event.drinkList;
    } else if (event is AddDrink) {
      List<Drink> newState = List.from(state);
      if (event.newDrink != null) {
        newState.add(event.newDrink);
      }
      yield newState;
    } else if (event is DeleteDrink) {
      List<Drink> newState = List.from(state);
      newState.removeAt(event.drinkIndex);
      yield newState;
    } else if (event is UpdateDrink) {
      List<Drink> newState = List.from(state);
      newState[event.drinkIndex] = event.newDrink;
      yield newState;
    }
  }
}

片段:

body: BlocProvider(
    create: (BuildContext context) => DrinkBloc(),
    child: Column(children: [
      Row(

我现在遇到的错误基本上是当我单击按钮添加饮料时(“饮料”旁边的按钮)

No ancestor could be found starting from the context that was passed to BlocProvider.of<DrinkBloc>().
The context used was: DrinkForm(state: _DrinkFormState#5d9c5)
BlocProvider.of() called with a context that does not contain a Bloc of type DrinkBloc.

现在的样子(底部可以,但上面的,饮料,不行,可能是因为我把整个东西都包在了 DrinkBloc 里,不知道如何改变它 )

ma​​in.dart

   class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<FoodBloc>(
      create: (context) => FoodBloc(),
      child: MaterialApp(
        title: 'Sqflite Tutorial',
        theme: ThemeData(
          primarySwatch: Colors.deepPurple,
        ),
        home: FoodList(),
      ),
    );
  }
}

【问题讨论】:

  • 也许把代码放在MultiBlocProvider的main中?

标签: flutter dart bloc


【解决方案1】:

您没有将DrinkBloc 提供/注入到小部件树中。

因此,当您尝试使用 BlocConsumer 访问 DrinkBloc bloc 时,它会尝试查找该 bloc 的祖先。由于它丢失了,它会抛出那个特定的错误 BlocProvider.of() called with a context that does not contain a Bloc of type DrinkBloc.

要提供/注入Drinkbloc,您可以使用BlocProvider,如下所示:

BlocProvider(
  create: (BuildContext context) => BlocA(),
  child: ChildA(),
);

将其称为 BlocConsumer 的祖先。

例如:

Scaffold(
      appBar: AppBar(title: Text("FoodList")),
      body:  BlocProvider(
                 create: (BuildContext context) => DrinkBloc(),
               child: Column(children: [
                          ...
                          ],
         );

【讨论】:

  • 是否可以发送整个代码(只需将您发送给我的那个插入到我链接的原始代码中),以便我能更好地理解它吗?很抱歉如果太麻烦了,我还在学习,所以很难全部掌握。 @乔伊特伦斯
  • @arbiter,没问题,只是添加了一个 sn-p 让您知道放置它的位置
  • 好的,这行得通,不再出现红屏,但我仍然遇到问题,它说No ancestor could be found starting from the context that was passed to BlocProvider.of&lt;DrinkBloc&gt;(),我添加了 Bloc 代码和更改的 sn-p 以及它的外观主帖。
  • 我把它改成了 DrinkBloc,这很奇怪,底部有效(食物部分),但顶部不会产生错误(在主帖中更新)。更新主帖@Joy Terence
  • 我看到您在点击图标时路由到DrinkForm 页面。如果你从那里尝试context.bloc&lt;DrinkBloc&gt;().add(...),那将因为DrinkForm 中的上下文不知道而失败。通过github issue 了解谁来实现这一目标。特别是this comment
【解决方案2】:

为了让 BlocConsumer 使用上下文,它应该知道它使用的 bloc,因此,called with a context that does not contain a Bloc of type DrinkBloc.

就像在flutter_bloc 文档中一样,您必须像这样定义提供者

BlocProvider(
  create: (BuildContext context) => DrinkBloc(),
  child: Widget("this widget's context contains DrinkBloc"),
);

因此,只需将它放在小部件树中您想要的位置较高的任何位置,并将 BlocConsumer 放在其中的任何位置。

【讨论】:

  • 如前所述,我非常感谢您的回答并将全部标记。是否可以在上下文中向我发送代码(将此 BlocProvider 添加到我的代码中),以便我可以看到它如何工作得最好,如前所述,我仍在学习 Flutter,所以最好看到它在行动中。基本上我只希望这些 Bloc 一个在另一个之上工作(每个都在 Expanded 小部件中)。 @Khashayar Motarjemi
猜你喜欢
  • 2011-04-14
  • 1970-01-01
  • 2011-02-25
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-26
相关资源
最近更新 更多