You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:28:11