问题描述
我已经成功地围绕 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 万中选择一个随机数,或者想出某种随机哈希生成器。我敢肯定我的逻辑存在一些缺陷,所以我仍然在倾听更好的方法!