"Could not find the correct Provider" 即使小部件也是在 Provider 添加到上下文之后构建的

"Could not find the correct Provider" even the widget is built after the Provider is added to context

我在尝试从提供商处获取数据时遇到问题。我和他们一起工作了很多次,所以我知道你可能遇到的所有常见错误,但这个错误让我抓狂。

我有一个简单的小部件,它从 PassesSelector 提供商获取数据:

class PassesSelector extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    List<Passes> passes = Provider.of<PassesSelectorManager>(context).passes;

    return Column(
      mainAxisAlignment: MainAxisAlignment.start,
      children: [
        DaysSelector(
          primaryColor: Colors.green,
          title: "Select pass",
          passDays: passes,
        ),
      ],
    );
  }
}

在另一个小部件中,我创建了一个 Multiprovider(因为需要更多提供者),我在其中初始化 PassesSelector 并在子部分中添加了一个 Builder,它接收一个包含两个文本的列,显示一些 PassesSelector Provider数据和 PassSelector 小部件:

class TicketSelectionPresenter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<PassesSelectorManager>(
          create: (_) => PassesSelectorManager()
        ),
      ],
      child: Builder(builder: (context) {
        return Column(
          children: [
            Text(context.read<PassesSelectorManager>().taxes.toString()),
            Text(context.read<PassesSelectorManager>().dayPasses.toString()),
            PassesSelector(),
          ],
        );
      }),
    );
  }
}

问题是列中的 Texts 正确显示了信息(因此,创建了提供程序)但是在呈现 PassesSelector() 时出现错误 Could not find the correct Provider<PassesSelectorManager> above this PassesSelector widget但我不明白为什么,就像收到的上下文没有提供者一样。我知道如果你推送一条路线,上下文会有所不同,但在这种情况下,我们只是向上下文添加一个小部件......

你可能想知道的事情:

到目前为止我尝试过的事情:

感谢任何帮助,谢谢!

我建议尝试将上下文的 PassesSelectorManager 提供程序传递给 PassesSelector。我认为您需要 watch 而不是 read 但我不知道您的 PassesSelectorManager 中有什么,例如是否有任何 notifyListeners 调用。试试这个代码:

class PassesSelector extends StatelessWidget {
  final PassesSelectorManager passesSelectionManager;
  const PassesSelector({required this.passesSelectionManager, Key? key})
   : super (key: key); 
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.start,
      children: [
        DaysSelector(
          primaryColor: Colors.green,
          title: "Select pass",
          passDays: passesSelectionManager.passes,
        ),
      ],
    );
  }
}

class TicketSelectionPresenter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<PassesSelectorManager>(
          create: (_) => PassesSelectorManager()
        ),
      ],
      builder: (context, child) {
        final passesSelectionManager = context.watch<PassesSelectorManager>();
        return Column(
          children: [
            passesSelectionManager.taxes.toString()),
            passesSelectionManager.dayPasses.toString()),
            PassesSelector(passesSelectionManager),
          ],
        );
      }),
    );
  }
}

编辑ListenableProvider的另一种方法:

你可以尝试使用ListenableProvider,这不是经常使用,但在某些情况下会很有用。删除我在原始答案中建议的 passesSelectionManager 成员表单 PassesSelector class 和构造函数,然后试试这个:

class TicketSelectionPresenter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<PassesSelectorManager>(
          create: (_) => PassesSelectorManager()
        ),
      ],
      builder: (context, child) {
        final passesSelectionManager = context.watch<PassesSelectorManager>();
        return Column(
          children: [
            passesSelectionManager.taxes.toString()),
            passesSelectionManager.dayPasses.toString()),
            // this is the new part
            ListenableProvider<PassesSelectorManager>.value(
              value: passesSelectionManager,
              child: PassesSelector()),
          ],
        );
      }),
    );
  }
}

几天来我们一直在处理其他事情,但我们又遇到了一个奇怪的错误,因为 Flutter/Provider 没有按预期工作。我们再次进行了大量研究,直到找到解决方案。

导入文件时,Visual Studio代码导入了一些小写的单词,而目录名称以大写字母开头。因此,创建提供程序的页面是从中实例化它的(这是一个示例,请注意 Providers 单词的书写方式):

import 'package:xxx/Application/Providers/pass_selector_manager.dart

当小部件阅读试图从以下位置获取它时:

import 'package:xxx/Application/providers/pass_selector_manager.dart

我们觉得很傻,我们一直在检查生成的每个小部件树和周围所有“困难”的东西,直到我们发现这一点。这几乎是一个模因,但好吧,最后,教训是在出现问题时检查你的导入,即使它们是自动导入的。