Flutter中如何用Riverpod实现下拉框联动刷新表格Widget?
问题根源
你的表格组件未重渲染的核心原因是:dashboardRepositoryProvider是普通Provider,它返回的DashboardRepository实例引用从未改变——即便你在fetchDashboard里更新了实例内部的_data变量,Riverpod也不会因为对象内部状态变化而通知监听者。普通Provider仅当返回的对象本身被替换时,才会触发组件重建。
解决方案
方案一:直接监听fetchDashboardData FutureProvider
既然你已经通过ref.refresh(fetchDashboardData(newValue))触发了数据请求,只需让表格组件监听这个FutureProvider的状态即可:
修改TableGenerator组件
class TableGenerator extends ConsumerWidget { // 接收当前选中的下拉框值,用于指定监听的Family实例 final String selectedName; const TableGenerator({Key? key, required this.selectedName}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { // 监听对应name的fetchDashboardData状态 final dashboardAsync = ref.watch(fetchDashboardData(selectedName)); return dashboardAsync.when( loading: () => const CircularProgressIndicator(), error: (err, stack) => Text('加载失败:$err'), data: (_) { // 数据加载完成后从仓库取最新值 final repo = ref.watch(dashboardRepositoryProvider); return SingleChildScrollView( scrollDirection: Axis.vertical, child: Row( children: [ const FixedColumnWidget(data: [ "one", "two", "three", "four", "fifth", ]), ScrollableColumnWidget(data: repo.dashboardData as DashboardData) ], ), ); }, ); } }
在父组件中传入选中值
// 示例:在使用TableGenerator的地方 final selectedName = ref.watch(dropItemProvider); TableGenerator(selectedName: selectedName)
当你调用ref.refresh(fetchDashboardData(newValue))时,FutureProvider的状态会更新,触发TableGenerator重建并渲染新数据。
方案二:用StateNotifierProvider管理可监听状态(推荐)
这是更符合Riverpod规范的做法,通过StateNotifier封装状态,让状态变化自动触发组件重建:
1. 重构仓库为StateNotifier
import 'package:flutter_riverpod/flutter_riverpod.dart'; class DashboardStateNotifier extends StateNotifier<DashboardData?> { DashboardStateNotifier(this.read) : super(null); final Reader read; List<dynamic>? _names; List<dynamic>? get names => _names; Future<void> fetchDashboard(String name) async { final token = await read(authServiceProvider).getToken(); final response = await read(clientProvider(token)) .get('/getData', queryParameters: {"name": name}); // 更新state,自动通知所有监听者 state = DashboardData.fromJson(response.data); } Future<void> fetchNames() async { final token = await read(authServiceProvider).getToken(); final response = await read(clientProvider(token)).get('/analystNames'); _names = response.data["names"]; } }
2. 创建对应的Provider
final dashboardStateProvider = StateNotifierProvider<DashboardStateNotifier, DashboardData?>((ref) { return DashboardStateNotifier(ref.read); }); // 保留获取名称的FutureProvider final fetchAnalystNames = FutureProvider((ref) { final notifier = ref.watch(dashboardStateProvider.notifier); return notifier.fetchNames(); });
3. 修改下拉框回调
onChanged: (String? newValue) { if (newValue == null) return; ref.read(dropItemProvider.notifier).state = newValue; // 直接调用notifier方法更新状态 ref.read(dashboardStateProvider.notifier).fetchDashboard(newValue); setState(() { widget.value = newValue; }); },
4. 修改TableGenerator组件
class TableGenerator extends ConsumerWidget { const TableGenerator({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { // 监听StateNotifier的状态 final dashboardData = ref.watch(dashboardStateProvider); return dashboardData != null ? SingleChildScrollView( scrollDirection: Axis.vertical, child: Row( children: [ const FixedColumnWidget(data: [ "one", "two", "three", "four", "fifth", ]), ScrollableColumnWidget(data: dashboardData) ], )) : const CircularProgressIndicator(); } }
这种方式将状态与UI解耦,状态变化会自动触发组件重建,无需手动处理刷新逻辑,是Riverpod推荐的状态管理方式。
内容的提问来源于stack exchange,提问作者Darshan
相关产品推荐
相关产品推荐

