“无法找到正确的提供商”甚至在将 Provider 添加到上下文之后构建小部件

发布于 2025-01-13 18:35:48 字数 2428 浏览 3 评论 0原文

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

我有一个简单的小部件,可以从 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 并在孩子,我添加一个生成器,它接收一个包含两个文本的列,显示一些 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() 时,我收到错误无法找到正确的 Provider;在此 PassesSelector 小部件上方 但我不明白为什么,就像收到的上下文没有提供者一样。我知道如果您推送路线,上下文会有所不同,但在这种情况下,我们只是向上下文添加一个 Widget...

您可能想知道的事情:

  • [√] Flutter(Channel stable,2.10.2,on Microsoft Windows [版本 10.0.19042.1526],语言环境 en-GB)
  • [√] VS Code(版本 1.65.2)
  • [√] Android 工具链 - 为 Android 设备开发(Android SDK 版本) 30.0.2)

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

  • 使用 builder(context, child) => MultiProvider 的 PassesSelector() 函数而不是 child
  • 在 Builder 列中添加 Consumer 并将 PassesSelector() 添加为子项
  • PassesSelector() 的构建函数中添加 Consumer
  • 放置所有带有 Texts 的列并PassesSelector 作为一个新的 Widget,同样的情况发生,文本可以正确显示数据,但小部件 PassesSelector() 会抛出错误。

如有任何帮助,我们将不胜感激,谢谢!

I'm having problems trying to obtain data from a provider. I've been working a lot with them so I know all the usual errors that you can get with, but this one is driving me crazy.

I have a simple widget that gets data from PassesSelector provider:

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,
        ),
      ],
    );
  }
}

In another widget, I create a Multiprovider (as there will be more providers needed) where I initialize the PassesSelector and in child, I add a Builder that receives a column with two texts showing some PassesSelector Provider data and the PassSelector widget:

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(),
          ],
        );
      }),
    );
  }
}

The thing is that the Texts inside the Column show the information properly (so, the provider is created) but when rendering the PassesSelector() I'm getting the error Could not find the correct Provider<PassesSelectorManager> above this PassesSelector widget but I don't understand why, like the context received did not have the provider. I know the context is different if you push a route, but in this case we're just adding a Widget to the context...

Things you might want to know:

  • [√] Flutter (Channel stable, 2.10.2, on Microsoft Windows [Version 10.0.19042.1526], locale en-GB)
  • [√] VS Code (version 1.65.2)
  • [√] Android toolchain - develop for Android devices (Android SDK version 30.0.2)

Things I tried so far:

  • Using the builder(context, child) => PassesSelector() function of MultiProvider instead of child
  • Add Consumer<PassesSelector> inside the Builder column and add PassesSelector() as child
  • Add Consumer<PassesSelector> inside the build function of PassesSelector()
  • Placed all the Column with Texts and PassesSelector as a new Widget, and the same happens, the Texts can show the data properly but the widget PassesSelector() throws the error.

Any help is appreciated, thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

饮惑 2025-01-20 18:35:48

我建议尝试将上下文的 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 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()),
          ],
        );
      }),
    );
  }
}

I would suggest to try to pass the context's PassesSelectorManager provider to PassesSelector. I think you need watch and not read but I don't know what's in your PassesSelectorManager, for example are there any notifyListeners called. Try this code:

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),
          ],
        );
      }),
    );
  }
}

EDIT: another approach with ListenableProvider:

You can try to use ListenableProvider, this is not used very often but can be useful in some cases. Remove the passesSelectionManager member form PassesSelector class and constructor I suggested in the original answer, and try this:

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()),
          ],
        );
      }),
    );
  }
}
萌辣 2025-01-20 18:35:48

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

导入文件时,Visual Studio Code 会导入一些小写单词,而目录名称以大写字母开头。因此,创建提供程序的页面正在实例化它(这是一个示例,请注意 Providers 一词是如何编写的):

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

而 Widget 读取试图从中获取它:

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

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

We've been a few days working on other things and we got again a weird error as Flutter/Provider was not working as expected. We did big research again until we found the solution.

When importing files, Visual Studio Code was importing some words in lower case while the directory name started with Caps. So, the page that was creating the provider was instantiating it from (it's an example, notice how the Providers word is written):

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

while the Widget reading was trying to obtain it from:

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

We feel silly, we've been checking each widget tree generated and all the "hard" stuff around until we found out this. It's almost a meme, but well, at the end, the lesson is to check your imports when something breaks, even if they're auto imported.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文