是否可以拥有多个完全相同类型的 Riverpod ChangeNotificationProvider? main.dartmainscreen.dartNewsScreen.dart新闻消费者.dart

问题描述

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

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

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

正如我所料,这两个页面共享相同的数据源。

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

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

所以从这个意义上说,它被两个标签页“全局”使用。

有没有什么策略可以让这两个页面独立获取数据?我不想使用不同的提供程序重新编码这个新页面的两个版本。理想情况下,根据用户想要的新闻页面标签数量,我希望在标签调用 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(),);
  }
}

新闻消费者.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。我希望他们能成为某种“孩子”并理解NewsProvider

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

解决方法

好的,使用上面 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;

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