flutter中使用redux之多界面互動

上一篇文章,咱們介紹瞭如何在flutter中使用redux。在上一篇文章的例子中,咱們使用了單界面集成redux,可是在實際項目中,咱們一般涉及多個模塊,每一個模塊涉及多個界面,那麼如何使用redux整合模塊,並實現模塊和界面間的消息傳遞呢?git

例子:登陸

接着上篇文章,此次的例子稍微複雜一點:github

目標:redux

  • 實現登陸界面,實現基本登陸邏輯
  • 成功以後將結果通知到其餘界面

clipboard.png

先將AppState等狀態有關的移動到reducers.dart,建立LoginPage.dartsegmentfault

LoginPage.dart代碼以下:app

import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_use_redux/reducers.dart';
import 'package:redux/redux.dart';
import 'dart:async';
import 'package:flutter/cupertino.dart';


typedef Future CallLogin(String account,String pwd);

class LoginPageState extends State<LoginPage>{

  String _account;
  String _pwd;



  bool isLogin;

  @override
  void initState() {
    super.initState();
  }

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


  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("登陸"),
      ),
      body: new Form(
          onChanged: (){
            print("changed");
          },
          onWillPop: () async{
            return true;
          },
          child: new Padding(padding: new EdgeInsets.all(10.0),child: new Column(

            children: <Widget>[
              new TextFormField( decoration:new InputDecoration(labelText: "請輸入帳號") ,
                onSaved: (String value){
                 _account = value;
                },  ///保持一下輸入的帳號
                validator: (String value)=> value.isEmpty ? "請輸入帳號" : null, ),
              new TextFormField(decoration:new InputDecoration(labelText: "請輸入密碼"),
                  onSaved: (String value)=>_pwd = value, ///保持一下輸入的密碼
                  validator: (String value)=> value.isEmpty ? "請輸入密碼" : null),
              new FormField(builder: (FormFieldState s){
                return new Center(
                  child: new RaisedButton(onPressed: () async{

                  FormState state = Form.of(s.context);
                  if(state.validate()){
                    //若是驗證成功,那麼執行登陸邏輯
                    state.save();
                    print("Login success $_account" );
                    //這裏交給設置好的邏輯去執行操做
                    try{
                      await widget.callLogin(_account,_pwd);
                      showDialog(context: context,builder: (c){

                        return new CupertinoAlertDialog(
                          title: new Text("登陸成功"),
                          actions: <Widget>[
                            new Center(
                              child: new RaisedButton(
                                onPressed:(){
                                  Navigator.of(context).pop();
                                  Navigator.of(context).pop();
                                },
                                child: new Text("ok"),
                              )
                            )
                          ],
                        );

                      });
                    //  Navigator.of(context).pop();
                    }catch(e){
                      showDialog(context: context,builder: (c){

                        return new CupertinoAlertDialog(
                          title: new Text("登陸失敗$e"),
                          actions: <Widget>[
                            new Center(
                                child: new RaisedButton(
                                  onPressed:(){
                                    Navigator.of(context).pop();
                                  },
                                  child: new Text("ok"),
                                )
                            )
                          ],
                        );

                      });
                      ///登陸失敗,提示一下用戶
                      print("登陸失敗! $e");
                    }

                  }

                },child: new Text("提交"),)
                );
              })
            ],

          ),)),
    );
  }

}

class LoginPage extends StatefulWidget{

  CallLogin callLogin;


  LoginPage({this.callLogin});

  @override
  State<StatefulWidget> createState() {
    return new LoginPageState();
  }

}
注意:這個組件其實並無使用redux,登陸邏輯使用外部傳遞過來的函數來處理:
CallLogin callLogin;
  LoginPage({this.callLogin});

 ...
//執行登陸邏輯
     await widget.callLogin(_account,_pwd);
 ...
爲何要這麼作呢?好處有哪些?
  • 減小組件之間的依賴關係
  • 減小本類的職責,將本類的職責變成只展現ui
  • 本類可單獨單元測試,單獨工做,只要傳進來一個模擬的邏輯函數
那麼在哪裏將登陸邏輯傳遞進來呢?

···
routes: {異步

"login":(BuildContext context)=>new StoreConnector(builder: ( BuildContext context,Store<AppState> store ){

      return new LoginPage(callLogin: (String account,String pwd) async{
        print("正在登陸,帳號$account,密碼:$pwd");
        // 爲了模擬實際登陸,這裏等待一秒
        await new Async.Future.delayed(new Duration(milliseconds: 1000));
        if(pwd != "123456"){
          throw ("登陸失敗,密碼必須是123456");
        }
        print("登陸成功!");
        store.dispatch(new LoginSuccessAction(account: account));

      },);
    }, converter: (Store<AppState> store){
      return store;
    }),

···async

在導入這個登陸組件到應用程序路由上面的時候,這個時候將邏輯和Store進行對接,這樣作,就將邏輯和ui完全的分開了。ide

這裏涉及到異步操做,那麼就會遇到所謂「反作用」問題。
隨着項目的增大,reducer也會愈來愈大,那麼有什麼辦法能夠管理呢?
這些問題咱們改天再分享。函數

附件:

老規矩,代碼在這裏:
https://github.com/jzoom/flut...單元測試

若有疑問,請加qq羣854192563討論

相關文章
相關標籤/搜索