11、Flutter Fish redux component实

2020-03-23  本文已影响0人  LogMan

本文主要记录个人在学习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

上一篇下一篇

猜你喜欢

热点阅读