如何在Flutter中使用Mobx弹出屏幕

时间:2019-06-02 04:52:51

标签: flutter dart mobx

我有一个Food对象,该对象包含名称,id,卡路里等属性。通过一系列屏幕,用户可以填充Food对象的属性。

完成后,用户可以按“提交”按钮,这将在商店中调用addFood方法。

问题是,将食物上传到服务器后,我想根据响应弹出屏幕或在烤面包上显示错误消息。我只是不知道该怎么做。

以下是我的代码(仅重要位): FoodDetailStore.dart

class FoodDetailStore = _FoodDetailStore with _$FoodDetailStore;

abstract class _FoodDetailStore with Store {
  Repository _repository;

  Food _food;

  @observable
  String msg = '';

  // ... Other Observables and actions

  @action
  addFood(bool toAdd) {
    if (toAdd) {
      _repository.addFood(food).then((docId) {
       if (docId != null) {
         // need to pop the screen
       }
      }).catchError((e) {
         // show error to the user.
         // I tried this, but it didn't work
         msg = 'there was an error with message ${e.toString()}. please try again.';
      });
    }

  // .. other helper methods.
}

FoodDetailScreen.dart (忽略集团参考,我目前正在将代码重构为mobx)

class FoodDataScreen extends StatefulWidget {
  final String foodId;
  final Serving prevSelectedServing;
  final bool fromNewRecipe;

  FoodDataScreen({@required this.foodId, this.prevSelectedServing, this.fromNewRecipe});

  @override
  _FoodDataScreenState createState() => _FoodDataScreenState(
        this.foodId,
        this.prevSelectedServing,
        this.fromNewRecipe,
      );
}

class _FoodDataScreenState extends State<FoodDataScreen> {
  final String foodId;
  final Serving prevSelectedServing;
  final bool fromNewRecipe;

  FoodDataBloc _foodDataBloc;

  _FoodDataScreenState(
    this.foodId,
    this.prevSelectedServing,
    this.fromNewRecipe,
  );

  FoodDetailStore store;

  @override
  void initState() {
    store = FoodDetailStore();
    store.initReactions();
    store.initializeFood(foodId);
    super.initState();
  }

 @override
 void didChangeDependencies() {
   super.didChangeDependencies();
   // I know this is silly, but this is what i tried. Didn't worked
   Observer(
    builder: (_) {
     _showMsg(store.msg);
    }
   );
 }

  @override
  Widget build(BuildContext context) {
    return Container(
    // ... UI  
    );
  }

  _popScreen() {
    _showMsg('Food Added');
    Majesty.router.pop(context);
  }

  _showMsg(String msg) {
    Fluttertoast.showToast(msg: msg);
  }

  @override
  void dispose() {
    store.dispose();
    super.dispose();
  }
}

1 个答案:

答案 0 :(得分:3)

Observer内构造didChangeDependencies()实例确实是“愚蠢的”,正如您已经正确指出的那样:) Observer是一个窗口小部件,需要将窗口小部件插入窗口小部件树中才能执行有用的操作。在我们的情况下,non-widget Mobx reactions进行了救援。

对于在发生明显变化时显示Snackbar的情况,我将在代码中演示如何做到这一点,以便您了解如何转换代码。

首先,导入import 'package:mobx/mobx.dart';。 然后在didChangeDependencies()中创建一个反应,该反应将使用您的一些观测值。在我的情况下,这些可观察对象是_authStore.registrationError_authStore.loggedIn

final List<ReactionDisposer> _disposers = [];

@override
void dispose(){
  _disposers.forEach((disposer) => disposer());
  super.dispose();
}

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  _authStore = Provider.of<AuthStore>(context);
  _disposers.add(
    autorun(
      (_) {
        if (_authStore.registrationError != null)
          _scaffoldKey.currentState.showSnackBar(
            SnackBar(
              content: Text(_authStore.registrationError),
              backgroundColor: Colors.redAccent,
              duration: Duration(seconds: 4),
            ),
          );
      },
    ),
  );
  _disposers.add(
    reaction(
      (_) => _authStore.loggedIn,
      (_) => Navigator.of(context).pop(),
    ),
  );
}

我在这里使用两种类型的Mobx反应:autorunreactionautorun会在您创建板条之后立即触发,然后每次观察对象更改其值。 reaction仅在可观察到的变化时才触发第一次。

还应注意以dispose()方法处理已创建的反应,以避免资源泄漏。

这是我的Mobx商店类的代码,其中使用了可观察的东西来完成图片:

import 'package:mobx/mobx.dart';

import 'dart:convert';

part "auth_store.g.dart";

class AuthStore = AuthStoreBase with _$AuthStore;

abstract class AuthStoreBase with Store{

  @observable
  String token;

  @observable
  String registrationError;

  @observable
  String loginError;

  @action
  void setToken(String newValue){
    token = newValue;
  }

  @action
  void setRegistrationError(String newValue){
    registrationError = newValue;
  }

  @action
  void setLoginError(String newValue){
    loginError = newValue;
  }

  @action
  void resetLoginError(){
    loginError = null;
  }

  @computed
  bool get loggedIn => token != null && token.length > 0;

  @action
  Future<void> logOut() async{
    setToken(null);
  }
}