是否可以有多个完全相同类型的 Riverpod ChangeNotificationProvider?

Is it possible to have multiple Riverpod ChangeNotificationProviders of the same exact type?

我已经围绕 riverpod ChangeNotificationProvider 成功构建了一个 NewsScreen 以从 REST api 轮询数据,然后创建一个列表视图。

我的应用有多个由底部标签导航控制的页面。在两个选项卡中,我想显示 NewsScreen.

两者都很好,但问题是数据源是一样​​的。这意味着如果我在第一页上加载第二页的新闻列表 API,另一个选项卡也会显示更多新闻项目。

这两个页面共享同一个数据源,正如我所预料的那样。

这就是我在 NewsScreen.dart 页面顶部声明我的 Provider 的方式

final NewsProvider = ChangeNotifierProvider<NewsData>((ref) {
  return NewsData();
});

所以从这个意义上说,它被两个标签页 'globally' 使用。

有什么策略可以让这两个页面独立获取数据吗?我不想使用不同的提供商重新编码这个新页面的两个版本。理想情况下,我会在选项卡中使用相同的代码调用 2 次(或更多),具体取决于用户想要多少个新闻页面选项卡

这是我的应用程序的一般结构,以防它有所帮助,但如果有人有任何关于如何执行此操作的提示,或者任何我可以阅读以弄清楚它的内容,我们将不胜感激!

main.dart

void main() {

  runApp(
    // Adding ProviderScope enables Riverpod for the entire project
    const ProviderScope(child: MyApp()),
  );

}


class MyApp extends StatelessWidget{
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    return  MaterialApp(
        title: Constants.appName,
        home:MainScreen()
        );


  }

mainscreen.dart

Standard persistent_bottom_navigation.   https://pub.dev/packages/persistent_bottom_nav_bar

My code can be provided if needed, but it calls NewsScreen() from 2 of the tabs on a bottom nav bar

NewsScreen.dart

final NewsProvider = ChangeNotifierProvider<NewsData>((ref) {
  return NewsData();
});



class NewsScreen extends StatefulWidget {
  NewsScreen({Key? key}) : super(key: key);


  @override
  _NewsScreenState createState() => _NewsScreenState();
}


class _NewsScreenState extends State<NewsScreen> {
  //NewsScreen({Key? key}) : super(key: key);

  int _allowNextPageLoad = 1;
  ScrollController _scrollController = ScrollController();


  @override
  void initState(){
    super.initState();

    /// LOAD THE DATA ONLY ON THE FIRST LOAD
    context.read(NewsProvider).fetchData;


     (... some scroll controller stuff ...)

  @override
  void dispose(){
      _scrollController.dispose();
      super.dispose();
  }


  @override
  Widget build(BuildContext context) {


    return
      Scaffold(
          appBar: AppBar(
              title: Text("News",
          ),
          body: RefreshIndicator(
            onRefresh: () async {
(...)
            },
            child: Center(
              child: Container(
                child: NewsScreenConsumer(),
            ),
          ),
          ),
      );
  }
}

NewsConsumer.dart

class NewsScreenConsumer extends ConsumerWidget {
  NewsScreenConsumer();


  @override
  Widget build(BuildContext context, ScopedReader watch)
  {
    /// PROVIDER SETUP
    final data = watch(NewsProvider);

        return Container ( ... UI using data from news provider ... );
   }
}

编辑

如果我按如下方式将 NewsProvider = ChangeNotifierProvider 移动到屏幕小部件中,它就可以正常工作了:

class _NewsScreenState extends State<NewsScreen> {

  final NewsProvider = ChangeNotifierProvider<NewsData>((ref) {
    return NewsData();
  });
...

但是出现了一个新问题,我有几个 UI 小部件依赖于来自 NewsProvider 的信息,并从 _NewsScreenState 内部调用以构建 UI(本质上是小部件在 NewsConsumer.dart)。这些不再具有访问不再全局的 NewsProvider 的权限。我希望他们能成为某种 'child' 并理解 NewsProvider

现在我可以将所有这些小部件的代码物理地移动到我的 _NewsScreenState 小部件中,以便它可以访问提供程序,但它不是很优雅。有没有办法将这个 NewsProvider 作为一种局部变量,仅用于为 NewsScreen 构建 UI 的几个 'child' 小部件?

好的,根据上面 Alex Hartford 的建议,我研究了 .family 概念,我发现了一些似乎有效的东西。

我把它放在这里是因为它可以帮助那里的任何人,但也因为有人注意到我的想法中存在一些明显的缺陷:

我所做的是通过将我的全局调用更改为这个

来切换到 NewsProvider .family
final NewsProvider = ChangeNotifierProvider.family<NewsData, int>((ref, id) {
  return NewsData();
});

然后在我的 class _NewsScreenState extends State<NewsScreen> { 中生成一个随机 # 作为我们将要使用的这个家庭成员的 ID

class _NewsScreenState extends State<NewsScreen> {

  int _randomNumber = Random().nextInt(100);
...

现在在我需要使用我的 Provider 的地方我这样称呼它

await context.read(NewsProvider(_randomNumber)).fetchData;

它现在似乎工作得很好。我想有可能会生成两次相同的随机数,所以我会让它从 10milllion 中选择一个随机数,或者可能想出某种随机哈希生成器。我确定我的逻辑存在一些缺陷,所以我仍然在倾听更好的方法!