美文网首页
11、Flutter Fish redux component实

11、Flutter Fish redux component实

作者: LogMan | 来源:发表于2020-03-23 17:00 被阅读0次

    本文主要记录个人在学习fish redux中的component部分,通过编写一个登录框架来加深理解。
    首先在lib下创建login包,通过右键fish redux Template,创建LoginPage。
    fish redux中的component是用来组成page中view的,所以是不能单独使用的,其中的用法在代码上表现的很直接:

    class LoginPage extends Page<LoginState, Map<String, dynamic>> {
      LoginPage()
          : super(
                initState: initState,
                effect: buildEffect(),
                reducer: buildReducer(),
                view: buildView,
                dependencies: Dependencies<LoginState>(
                    adapter: null,
                    slots: <String, Dependent<LoginState>>{
                      'smsComponent':
                        SmsLoginConnector() + SmsComponent(),
                      'pwdComponent':
                        PwdLoginConnector() + PwdComponent(),
                    }),
                middleware: <Middleware<LoginState>>[
                ],);
    }
    

    代码中的slots,依赖于smsComponent及pwdComponent两个子组件,通过连接器将LoginPage与SmsComponent、PwdComponent联系起来。
    看到这里,明白SmsComponent跟PwdComponent是LoginPage的子组件,在login目录下面,按照创建LoginPage方式,创建出来两个component——PwdComponent&SmsComponent。至此,已经完成了login界面目录结构上的搭建。

    loginPage结构图.png

    然后,开始使用component来组装页面(page)了:
    第一步,在LoginState(State文件)中,初始化state,loginState是Loginpage的state,其中应该包含子组件的state的初始化及创建联系:

    class LoginState implements Cloneable<LoginState> {
      SmsState smsState;
      PwdState pwdState;
      bool isSmsModel;
    
      @override
      LoginState clone() {
        return LoginState()
          ..smsState = smsState
          ..pwdState = pwdState
          ..isSmsModel=isSmsModel;
      }
    }
    
    LoginState initState(Map<String, dynamic> args) {
      return LoginState()..isSmsModel = true
      ..pwdState = PwdState(loginBtnEnable: false)//初始化pwdComponent中按键的状态
      ..smsState = SmsState(loginBtnEnable: false);//初始化smsComponent中按键的状态
    }
    //smsComponent与page的连接器
    class SmsLoginConnector extends ConnOp<LoginState,SmsState>{
      @override
      SmsState get(LoginState state) {
        return state.smsState;
      }
      @override
      void set(LoginState state, SmsState subState) {
        state.smsState = subState;
      }
    }
    //pwdComponent与page的连接器
    class PwdLoginConnector extends ConnOp<LoginState,PwdState>{
      @override
      PwdState get(LoginState state) {
        return state.pwdState;
      }
      @override
      void set(LoginState state, PwdState subState) {
        state.pwdState = subState;
      }
    }
    

    第二步,在view中引用smsComponent及pwdComponent。
    通过 state中的isSmsModel来确定引用当前那个子组件:

    Widget buildView(LoginState state, Dispatch dispatch, ViewService viewService) {
      return Scaffold(
        backgroundColor: Colors.white,
        body: Container(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
            ......
              _getLoginView(state,viewService),//引入子组件
            ],
          ),
        ),
      );
    }
    //判断当前的isSmsModel,加载不同的组件
    Widget _getLoginView(LoginState state,ViewService viewService){
      if(!state.isSmsModel){
        return Container(
          child: viewService.buildComponent('smsComponent'),
        );
      }else{
        return Container(
          child: viewService.buildComponent('pwdComponent'),
        );
      }
    }
    

    state.isSmsModel是由页面顶部的“密码登录”跟“验证码登录”两个按键控制的,具体实现可以参考GitHub中的具体代码。
    第三步,实现验证码登录及密码登录的切换
    在login的Action中创建pwdLogin,及smsLogin两个意图,view中的密码登录及验证码登录按键,触发这两个意图,并发送(dispatch)给effect,拿到pwdLogin及smsLogin两个意图的effect将该意图,再次发生(dispatch)给reducer,然后通过reducer来更新当前的state,并更新view。

    ......
    LoginState _pwdLogin(LoginState state, Action action){
      final LoginState newState = state.clone();
      newState.isSmsModel = false;
      return newState;
    }
    

    第四步,完善component
    component的state中包含一个bool类型的状态loginBtnEnable,表示登录按钮是否可用。在LoginPage state中默认值为false。接下来是component的view:

    Widget buildView(PwdState state, Dispatch dispatch, ViewService viewService) {
      return Container(
        margin: EdgeInsets.only(left: 30, top: 40, right: 30),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Container(
              child: TextField(
                decoration: InputDecoration(
                  hintText: "请输入手机号码",
                  hintStyle: TextStyle(color: Colors.grey[300], fontSize: 14),
                  border: InputBorder.none,
                ),
                cursorColor: Color(0xFF009274),
              ),
              decoration: BoxDecoration(
                  // 下滑线浅灰色,宽度1像素
                  border: Border(
                      bottom: BorderSide(color: Colors.grey[300], width: 0.5))),
            ),
            Stack(
              children: <Widget>[
                Container(
                  margin: EdgeInsets.only(top: 20),
                  child: TextField(
                    decoration: InputDecoration(
                      hintText: "请输入验证码",
                      hintStyle: TextStyle(color: Colors.grey[300], fontSize: 14),
                      border: InputBorder.none,
                    ),
                    obscureText: true,
                    cursorColor: Color(0xFF009274),
                  ),
                  decoration: BoxDecoration(
                    // 下滑线浅灰色,宽度1像素
                      border: Border(
                          bottom: BorderSide(color: Colors.grey[300], width: 0.5))),
                ),
              ......//详细代码,请参考Github
    }
    

    到这里,我们就完成了多个component组件组装一个page,以上都是开发思路,具体实现可参考https://github.com/zjt19870816/fish_redux_login

    相关文章

      网友评论

          本文标题:11、Flutter Fish redux component实

          本文链接:https://www.haomeiwen.com/subject/geksyhtx.html