如何使用Mobx编写周期性服务器连接检测的ReactionBuilder?
用Mobx的ReactionBuilder实现周期性服务器连接检测与重试
问题描述
我想通过Mobx的ReactionBuilder实现周期性检测服务器连接,连接失败时自动重试(最多4次),成功后跳转到登录页。不考虑使用Stream方案,希望完全基于Mobx的响应式理念实现。
现有页面状态类代码:
abstract class LandingPageStateBase with Store { final IempServerRepositoryBase _iempServerRepository; var counterTryToConnect = 0; ... @observable bool isLoading = false; // 假设connection是已定义的可观察变量 @observable dynamic connection; ... @action Future<void> getTestConnection() async { counterTryToConnect += 1; isLoading = true; connection = null; try { final data = await _iempServerRepository.getConnection(); connection = data; } on Exception catch (_) { connection = null; } isLoading = false; } bool isConnected() { return connection != null && !isLoading; } }
现有Widget代码片段:
@override Widget build(BuildContext context) { return CupertinoPageScaffold( child: SafeArea( child: ReactionBuilder( builder: (context) { _landingPageState.getTestConnection(); // 这里需要判断连接状态,失败则重试 return reaction((_) => _landingPageState.isLoading, (_) { if (!_landingPageState.isConnected() && _landingPageState.counterTryToConnect < 4) { _landingPageState.getTestConnection(); } else if (_landingPageState.isConnected()) { Future.delayed(const Duration(milliseconds: 500), () { setState(() { Navigator.pushReplacement( context, CupertinoPageRoute( builder: (context) => const LogInPage())); }); }); } debugPrint('debug: ${_landingPageState.counterTryToConnect}'); }, delay: 1000); }, ...
解决方案
1. 优化状态类
首先把重试次数改成可观察变量,让Mobx能追踪其变化;同时增加并发控制,避免同一时间发起多个连接请求:
abstract class LandingPageStateBase with Store { final IempServerRepositoryBase _iempServerRepository; @observable int counterTryToConnect = 0; @observable bool isLoading = false; @observable dynamic connection; ... @action Future<void> getTestConnection() async { // 如果正在加载,直接返回,避免并发请求 if (isLoading) return; counterTryToConnect += 1; isLoading = true; connection = null; try { final data = await _iempServerRepository.getConnection(); connection = data; // 连接成功后重置重试次数 counterTryToConnect = 0; } on Exception catch (_) { connection = null; } isLoading = false; } @computed bool get isConnected => connection != null && !isLoading; }
2. 修正ReactionBuilder的使用逻辑
ReactionBuilder的核心是通过reaction或autorun监听可观察状态的变化,触发对应的逻辑。这里我们需要监听连接状态和重试次数,实现延迟重试:
@override Widget build(BuildContext context) { return CupertinoPageScaffold( child: SafeArea( child: ReactionBuilder( builder: (context) { // 首次触发连接测试 if (_landingPageState.counterTryToConnect == 0) { _landingPageState.getTestConnection(); } // 监听连接状态和重试次数,触发重试或跳转 return reaction((_) => _landingPageState.isConnected || _landingPageState.counterTryToConnect, (_) { final state = _landingPageState; // 连接成功,跳转登录页 if (state.isConnected) { Future.delayed(const Duration(milliseconds: 500), () { Navigator.pushReplacement( context, CupertinoPageRoute(builder: (context) => const LogInPage()), ); }); return; } // 未达到重试上限,延迟发起下一次连接测试 if (state.counterTryToConnect < 4 && !state.isLoading) { Future.delayed(const Duration(seconds: 1), () { state.getTestConnection(); }); } debugPrint('重试次数: ${state.counterTryToConnect}'); }, ); }, ), ), ); }
关键要点说明
- 并发控制:在
getTestConnection中判断isLoading,避免同一时间发起多个连接请求,防止资源浪费。 - 可观察变量追踪:把
counterTryToConnect改为@observable,让Mobx能感知其变化,从而触发reaction逻辑。 - 逻辑解耦:用
@computed定义isConnected,替代原来的方法,更符合Mobx的响应式规范。 - 延迟重试:通过
Future.delayed实现重试间隔,避免频繁请求服务器;同时在reaction中监听状态变化,确保只有在状态改变时才触发下一次操作。 - 导航优化:跳转登录页时不需要调用
setState,因为Mobx的响应式已经处理了页面更新,直接调用Navigator即可。
内容的提问来源于stack exchange,提问作者qucals
相关产品推荐
相关产品推荐

