本文主要记录个人在学习fish redux中的component部分,通过编写一个登录框架来加深理解。
首先在lib下创建login包,通过右键fish redux Template,创建LoginPage。
fish redux中的component是用来组成page中view的,所以是不能单独使用的,其中的用法在代码上表现的很直接:
class LoginPage extends Page> {
LoginPage()
: super(
initState: initState,
effect: buildEffect(),
reducer: buildReducer(),
view: buildView,
dependencies: Dependencies(
adapter: null,
slots: >{
'smsComponent':
SmsLoginConnector() + SmsComponent(),
'pwdComponent':
PwdLoginConnector() + PwdComponent(),
}),
middleware: >[
],);
}
代码中的slots,依赖于smsComponent及pwdComponent两个子组件,通过连接器将LoginPage与SmsComponent、PwdComponent联系起来。
看到这里,明白SmsComponent跟PwdComponent是LoginPage的子组件,在login目录下面,按照创建LoginPage方式,创建出来两个component——PwdComponent&SmsComponent。至此,已经完成了login界面目录结构上的搭建。
然后,开始使用component来组装页面(page)了:
第一步,在LoginState(State文件)中,初始化state,loginState是Loginpage的state,其中应该包含子组件的state的初始化及创建联系:
class LoginState implements Cloneable {
SmsState smsState;
PwdState pwdState;
bool isSmsModel;
@override
LoginState clone() {
return LoginState()
..smsState = smsState
..pwdState = pwdState
..isSmsModel=isSmsModel;
}
}
LoginState initState(Map args) {
return LoginState()..isSmsModel = true
..pwdState = PwdState(loginBtnEnable: false)//初始化pwdComponent中按键的状态
..smsState = SmsState(loginBtnEnable: false);//初始化smsComponent中按键的状态
}
//smsComponent与page的连接器
class SmsLoginConnector extends ConnOp{
@override
SmsState get(LoginState state) {
return state.smsState;
}
@override
void set(LoginState state, SmsState subState) {
state.smsState = subState;
}
}
//pwdComponent与page的连接器
class PwdLoginConnector extends ConnOp{
@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: [
......
_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: [
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: [
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