对多个页面使用相同的 riverpod 状态提供程序

Using same riverpod state provider for multiple pages

我正在使用 provider 进行状态管理(实际上 riverpod) 在我的项目中,我有一个选项卡视图并将每个选项卡用于一个类别,每个选项卡都显示新闻列表。 tabview 大小不固定,我对所有选项卡使用相同的页面并将类别 id 传递给页面。

问题是 newsProvider 总是保留最后一个类别 ID,并且所有页面都显示相同的新闻列表。 谁可以为每个页面单独列出 newsProvider 列表?

//create tabview in my stateFullWidget
@override
Widget build(BuildContext context) {
   return Scaffold(
   body: DefaultTabController(
     length: europeanCountries.length, // europeanCountries has dynamic size
         child: new Scaffold(
            appBar: new AppBar(
                 
            flexibleSpace: new Column( 
               children: [
                  new TabBar( 
                      tabs: europeanCountries.map<Widget>((e) => getTab(e, FontAwesomeIcons.newspaper)).toList()),
                    ],
                  ),
                ),

               // dynamically create NewsList and pass category id
                body: TabBarView(children: europeanCountries.map((catItem) => NewsList(category: Category(title: catItem.title, id:catItem.id))).toList()),
              ),
            )
       )
 }

class NewsList extends StatefulWidget {
  Category category;

  NewsList({this.category});

  @override
  State<StatefulWidget> createState() {
    return _NewsListState(category:category);
  }
}

class _NewsListState extends State<NewsList> with AutomaticKeepAliveClientMixin<NewsList> {
  Category category;

  _NewsListState({this.category});
  
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      context.read(newsProvider).getNewsList(category.id);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Consumer(builder: (ctx, watch, child) {
      return watch(newsProvider.state).map(
        init: (value) {
          return Container();
        },
        loading: (value) {
          return Container(
            child: Center(
              child: CircularProgressIndicator(),
            ),
          );
        },
        success: (value) {
          return Container(child: getNewsItem(value.newsList));
        },
        serverError: (value) {
          return Container();
        },
      );
    });
  }

  @override
  bool get wantKeepAlive => true;
}




final newsProvider = StateNotifierProvider.autoDispose<NewsListNotifier>((ref) {
  var newsService = ref.watch(newsServiceProvider);
  return NewsListNotifier(newsService);
});

class NewsListNotifier extends StateNotifier<NewsListState> {
  final NewsService serviceRepository;


  NewsListNotifier(this.serviceRepository) : super(NewsListState.init());


  getNewsList(int catID) async {
    state = NewsListState.loading();
    DataResponse request = await serviceRepository.getNewsList(catID);
    request.maybeWhen(
      success: (value) {

        if (value.data != null) {
          state = NewsListState.success(newsList: value.data);
        }
      },
      error: (error) {
        state = NewsListState.serverError(error);
      },
      orElse: () {},
    );
  }

}

我终于找到了答案。谢谢@EdwynZN 通过使用 family 关键字,我可以为每个类别创建类似家庭的东西

class NewsList extends StatefulWidget {
  Category category;

  NewsList({this.category});

  @override
  State<StatefulWidget> createState() {
    return _NewsListState(category:category);
  }
}


class _NewsListState extends State<NewsList> with AutomaticKeepAliveClientMixin<NewsList> {
  Category category;

  _NewsListState({this.category});
  
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
     
      // add category.id to newsProvider, instead of getNewsList()
      context.read(newsProvider(category.id)).getNewsList();
    });
  }


  @override
  Widget build(BuildContext context) {
    return Consumer(builder: (ctx, watch, child) {

      //newsProvider(category.id) just listen to specific category id and not listen to all ids
      return watch(newsProvider(category.id).state).map( 
        init: (value) {
          return Container();
        },
        loading: (value) {
          return Container(
            child: Center(
              child: CircularProgressIndicator(),
            ),
          );
        },
        success: (value) {
          return Container(child: getNewsItem(value.newsList));
        },
        serverError: (value) {
          return Container();
        },
      );
    });
  }


  @override
  bool get wantKeepAlive => true;
}

//using family here and pass <My State, Category id>
final newsProvider = StateNotifierProvider.family<NewsListNotifier, int>((ref, catID) {
  var newsService = ref.watch(newsServiceProvider);
  return NewsListNotifier(newsService, catID);
});

class NewsListNotifier extends StateNotifier<NewsListState> {
  final NewsService serviceRepository;
  int catID;

  NewsListNotifier(this.serviceRepository, this.catID) : super(NewsListState.init());


  getNewsList() async {
    state = NewsListState.loading();
    DataResponse request = await serviceRepository.getNewsList(catID, page, 20);

    request.maybeWhen(
      success: (value) {

        if (value.data != null) {
          state = NewsListState.success(newsList: value.data);
        }
      },
      error: (error) {
        state = NewsListState.serverError(error);
      },
      orElse: () {},
    );
  }

}