Flutter中基于Redux标记返回页面时重新获取数据失败问题
问题:Flutter Redux页面返回后未触发数据重新获取
我开发了一个采用Redux状态管理的Flutter应用,需求是当其他页面的数据发生变更时,当前页面重新从服务器获取对应数据。具体场景:从Screen1跳转至Screen2,在Screen2完成数据修改后,将Redux中存储的布尔标记needUpdate设为true,但返回Screen1后,并未触发数据重新获取操作。
相关代码
FirstScreen代码
class FirstScreen extends StatefulWidget { const FirstScreen({Key? key}) : super(key: key); @override State<StatefulWidget> createState() => _FirstScreenState(); } class _FirstScreenState extends State<FirstScreen> { @override void initState() { super.initState(); } @override void didChangeDependencies() async { final store = StoreProvider.of<AppState>(context); var needUpdate = store.state.commonState?.needUpdate.value ?? false; if (needUpdate) { await store.dispatch(prepareData(context)); } } @override Widget build(BuildContext context) {} }
SecondScreen代码
class SecondScreen extends StatefulWidget { const SecondScreen({Key? key}) : super(key: key); @override State<SecondScreen> createState() => _SecondScreenState(); } class _SecondScreenState extends State<SecondScreen> { @override void initState() { super.initState(); } void onPress() async { await store.dispatch(ChangeNeedUpdatePortfolio(true)); Navigator.pop(context); } @override Widget build(BuildContext context) {} }
Action代码
ThunkAction<AppState> updatePortfolioData(BuildContext context) { return (Store<AppState> store) async { bool needUpdate = store.state.commonState?.needUpdate.value ?? false; if (needUpdate) { ... await store.dispatch(ChangeNeedUpdatePortfolio(false)); ... return; } }; }
问题原因
didChangeDependencies执行时机不符:这个方法仅在组件依赖(比如InheritedWidget)变更时触发,从Screen2返回Screen1时,Screen1的依赖没有发生变化,所以不会调用该方法,自然不会检查needUpdate状态。- 未订阅Redux状态变化:Screen1没有监听store的状态更新,即使
needUpdate被设为true,也无法感知到变化并执行数据获取逻辑。 - SecondScreen的store未正确获取:代码中直接使用
store.dispatch,但未看到store实例的获取逻辑,可能存在未初始化的问题。
解决方案
方案一:利用页面返回值直接触发更新(简单直接)
不需要依赖Redux的needUpdate标记,在返回Screen1时直接传递更新信号:
- 修改SecondScreen的
onPress方法:void onPress() async { // 先完成数据修改操作 final store = StoreProvider.of<AppState>(context); await store.dispatch(ChangeNeedUpdatePortfolio(true)); // 若需维护Redux状态保留此行 Navigator.pop(context, true); // 返回时携带需要更新的标记 } - 在Screen1的跳转逻辑中监听返回结果:
// 假设Screen1中跳转至SecondScreen的方法 void navigateToSecondScreen() async { final shouldUpdate = await Navigator.push( context, MaterialPageRoute(builder: (context) => const SecondScreen()), ); if (shouldUpdate == true) { final store = StoreProvider.of<AppState>(context); await store.dispatch(prepareData(context)); // 若需重置Redux中的needUpdate await store.dispatch(ChangeNeedUpdatePortfolio(false)); } }
方案二:订阅Redux状态变化(标准Redux做法)
让Screen1监听store的状态变更,当needUpdate变为true时自动触发数据获取:
- 修改FirstScreen的State类:
class _FirstScreenState extends State<FirstScreen> { late Store<AppState> _store; StreamSubscription? _storeSubscription; @override void initState() { super.initState(); _store = StoreProvider.of<AppState>(context); // 订阅store状态变化 _storeSubscription = _store.onChange.listen((newState) { final needUpdate = newState.commonState?.needUpdate.value ?? false; if (needUpdate) { _fetchData(); } }); // 页面初始化后检查一次状态 WidgetsBinding.instance.addPostFrameCallback((_) { final needUpdate = _store.state.commonState?.needUpdate.value ?? false; if (needUpdate) { _fetchData(); } }); } Future<void> _fetchData() async { await _store.dispatch(prepareData(context)); // 你的prepareData action中已经会把needUpdate设为false,无需重复处理 } @override void dispose() { _storeSubscription?.cancel(); // 取消订阅,避免内存泄漏 super.dispose(); } @override Widget build(BuildContext context) { // ... 页面布局代码 } } - 修复SecondScreen的store获取问题:
void onPress() async { final store = StoreProvider.of<AppState>(context); await store.dispatch(ChangeNeedUpdatePortfolio(true)); Navigator.pop(context); }
内容的提问来源于stack exchange,提问作者Mohamadamin
相关产品推荐
相关产品推荐

