Python

Flutter用fish_redux踩坑和实战

2019-11-19  本文已影响0人  红发_KVO

Fish_redux开发flutter的入门教学

1.Fish_redux的初相识

Fish Redux 是一个基于 Redux 数据管理的组装式 flutter 应用框架, 它特别适用于构建中大型的复杂应用。

它的特点是配置式组装。 一方面我们将一个大的页面,对视图和数据层层拆解为互相独立的 Component|Adapter,上层负责组装,下层负责实现; 另一方面将 Component|Adapter 拆分为 View,Reducer,Effect 等相互独立的上下文无关函数。

所以它会非常干净,易维护,易协作!
我们先看看fish_redux的官方GitHub给出的架构图!


fish_redux架构图.png,来自fish_redux团队的GitHub

1.1 Fish_redux的组成

page代表一个完整的页面,也就是我们理解的activity或者UIViewController。它由redux里面分层的viewstatereducereffectaction组成。这就是所谓的组装拔插式...你懂的(#^.^#)

class HomePage extends Page<HomeState, Map<String, dynamic>> {
 HomePage()
     : super(
           initState: initState,//生命周期
           effect: buildEffect(),//处理副作用的action
           view: buildView,//界面view
           dependencies: Dependencies<HomeState>(
               adapter: NoneConn<HomeState>() + HomeAdapter(),//高性能的listview适配器
               slots: <String, Dependent<HomeState>>{
               }),//用到的挂件,也就是组件components
           middleware: <Middleware<HomeState>>[
           ],);//oop切片,可以监听某些方法和生命周期的执行

}

state主要用来保存page或者component(页面/组件)的状态或者说属性,用来存放数据。

class HomeState implements Cloneable<HomeState> {
 EasyRefreshController refreshController;
 List<HandoverDataModel> list;
 int page;
 @override//必须复写的方法
 HomeState clone() {
   return HomeState()
   ..list = list
   ..refreshController = refreshController
   ..page = page;
 }
}
//初始化状态,也就是给页面的数据初始化等
HomeState initState(Map<String, dynamic> args) {
 HomeState homeState = HomeState();
 homeState.refreshController = new EasyRefreshController();
 homeState.list = new List();
 homeState.page = 1;
 return homeState;
}
//定义我们的意图,一般为枚举,命名最好是词达意
//Effect 接受处理的 Action,以 on{Verb} 命名
//Reducer 接受处理的 Action,以{verb} 命名
//playload用来约束参数类型
enum HomeAction { onLoad, onRefresh }

//effect的action
class HomeActionCreator {
 static Action onLoad(int page) {
   return  Action(HomeAction.onLoad,payload: page);
 }

 static Action onRefresh(){
   return  Action(HomeAction.onRefresh);
 }
}
enum HandOverAction { reloadData, loadMoreData }
// reducer的action
class HandOverActionCreator {
  static Action reloadData(List<HandoverDataModel> list) {
    return Action(HandOverAction.reloadData,payload: list);
  }

  static Action loadMoreData(List<HandoverDataModel> list) {
    return Action(HandOverAction.loadMoreData,payload: list);
  }

}
Reducer<HomeState> buildReducer() {
  return asReducer(
    <Object, Reducer<HomeState>>{
      HandOverAction.reloadData: _reloadData,
      HandOverAction.loadMoreData:_loadMoreData,
    },
  );
}

HomeState _reloadData(HomeState state, Action action) {
  final HomeState newState = state.clone();
//  newState.list.clear();
  newState.list = action.payload;
  return newState;
}

HomeState _loadMoreData(HomeState state, Action action){
  final HomeState newState = state.clone();
  newState.list.addAll(action.payload);
  return newState;
}

Effect会接收来自View的"意图",包括对应的生命周期的回调,然后做出具体的执行,例如页面跳转,dialog弹出等!它的处理可能是一个异步函数,数据可能在过程中被修改,所以我们应该通过 context.state 获取最新数据。 如果它要修改数据,应该发一个 ActionReducer 里去处理。它对数据是只读的,不能直接去修改数据

Effect<HomeState> buildEffect() {
  return combineEffects(<Object, Effect<HomeState>>{
    Lifecycle.initState:_init,
    HomeAction.onLoad: _onLoad,
    HomeAction.onRefresh: _onRefresh,
  });
}

void _init(Action action, Context<HomeState> ctx){
  ctx.dispatch(HomeActionCreator.onRefresh());
}

void _onLoad(Action action, Context<HomeState> ctx) {
  int page = action.payload;
  println("onload$page");
  NetUtlis.get("/utdcjjb/fdjiaojiebanlog/list.do?filter={'gangweiCode_\$equal':'5'}&page=$page&rows=10&sidx=lrtime&sord=desc",success: (value){
    ctx.state.page += 1;
    HandoverEntity entity = HandoverEntity.fromJson(value);
    ctx.state.refreshController.finishLoad(noMore: entity.data.xList.length <10);
    ctx.dispatch(HandOverActionCreator.onLoadMoreData(entity.data.xList));//转发到reducer去处理数据变化
  },failure: (error){
    print(error);
  });
}

void _onRefresh(Action action,Context<HomeState> ctx){
  int page = 1;
  ctx.state.page = 1;
  NetUtlis.get("/utdcjjb/fdjiaojiebanlog/list.do?filter={'gangweiCode_\$equal':'5'}&page=$page&rows=10&sidx=lrtime&sord=desc",success: (value){
    ctx.state.page += 1;
    HandoverEntity entity = HandoverEntity.fromJson(value);
    ctx.state.refreshController.resetLoadState();
    ctx.state.refreshController.finishRefresh();
    ctx.dispatch(HandOverActionCreator.onReloadData(entity.data.xList));//转发到reducer去处理数据变化
  },failure: (error){
    print(error);
  });
}

Widget buildView(HomeState state, Dispatch dispatch, ViewService viewService) {
  final ListAdapter adapter = viewService.buildAdapter();//适配器
  return Scaffold(
    appBar: PreferredSize(
      preferredSize: Size.fromHeight(50.0),
      child: AppBar(
        automaticallyImplyLeading: false,
        centerTitle: true,
        elevation: 0,
        title: Text('值长日志'),
      ),
    ),
    body: SafeArea(
      child: EasyRefresh(
//        bottomBouncing: false,
//        topBouncing: false,
        header: ClassicalHeader(),
        footer: ClassicalFooter(
          enableInfiniteLoad: false,
          enableHapticFeedback: false,
        ),
        controller: state.refreshController,
        onRefresh: () async{
          dispatch(HomeActionCreator.onRefresh());//意图回调
        },
        onLoad: () async{
          dispatch(HomeActionCreator.onLoad(state.page));
        },
        child: ListView.builder(
          itemBuilder: adapter.itemBuilder,
          itemCount: adapter.itemCount,
        ),
      ),
    ),
  );

}
class _HomeConnector extends ConnOp<HomeState, List<ItemBean>> {
//HomeState是大page的数据,handover是列表item的数据,通过大数据给小数据赋值
  @override 
  List<ItemBean> get(HomeState state) {
    if(state.list?.isNotEmpty == true){
      return state.list.map<ItemBean>((m){
        HandOverState handOverState = new HandOverState();
        handOverState.handoverDataModel = m;
            return ItemBean("handover", handOverState);
      }).toList();
    }else{
      return<ItemBean>[];
    }
  }
//小数据发生改变,回传给大数据
  @override
  void set(HomeState state, List<ItemBean> items) {
    if(items.isNotEmpty == true){
      state.list = List<HandoverDataModel>.from(items.map((m){
        return m;
    }).toList());
  }else{
      state.list = new List();
    }
  }

  @override
  subReducer(reducer) {
    // TODO: implement subReducer
    return super.subReducer(reducer);
  }
}

///register in component,真实数据没接入component,所以拷贝的官方数据
class ItemComponent extends ItemComponent<ItemState> {
  ItemComponent()
      : super(
          view: buildItemView,
          reducer: buildItemReducer(),
          dependencies: Dependencies<ItemState>(
            slots: <String, Dependent<ItemState>>{
              'appBar': AppBarComponent().asDependent(AppBarConnector()),
              'body': ItemBodyComponent().asDependent(ItemBodyConnector()),
              'ad_ball': ADBallComponent().asDependent(ADBallConnector()),
              'bottomBar': BottomBarComponent().asDependent(BottomBarConnector()),
            },
          ),
        );
}

///call in view
Widget buildItemView(ItemState state, Dispatch dispatch, ViewService service) {
  return Scaffold(
      body: Stack(
        children: <Widget>[
          service.buildComponent('body'),
          service.buildComponent('ad_ball'),
          Positioned(
            child: service.buildComponent('bottomBar'),
            left: 0.0,
            bottom: 0.0,
            right: 0.0,
            height: 100.0,
          ),
        ],
      ),
      appBar: AppbarPreferSize(child: service.buildComponent('appBar')));
}

其中Adapter有三种实现,我们需要继承其中一种

我们了解完基础的fish_redux库的一些基本组成了,在这个基础上,我们来看一下用fish_redux编写flutter的目录结构,主要借助于闲鱼团队提供的插件FishReduxTemplate我们省了很多功夫(剩下的就是命名和自己组合的能力了)

lib//主要编写代码目录
├── app.dart//主入口
├── entity_factory.dart//模型工厂辅助类
├── home//主页面
│   ├── action.dart
│   ├── effect.dart
│   ├── home_adapter//适配器
│   │   ├── action.dart
│   │   ├── adapter.dart
│   │   └── reducer.dart
│   ├── home_component//组件
│   │   ├── action.dart
│   │   ├── component.dart
│   │   ├── effect.dart
│   │   ├── reducer.dart
│   │   ├── state.dart
│   │   └── view.dart
│   ├── page.dart
│   ├── state.dart
│   └── view.dart
├── login//login页面
│   ├── action.dart
│   ├── effect.dart
│   ├── page.dart
│   ├── state.dart
│   └── view.dart
├── main.dart
└── network//网络请求和模型实体类
    ├── handover_entity.dart
    ├── netuntil.dart
    └── user_info_entity.dart

看完以上我们再来了解一下fish_redux的的工作流程:


flutter流程.png--网上来源

整体流程如下:
用户进行某个操作----->然后调用context.dispatch方法发送一个由ActionCreator创建的Action----->effect接收并处理,然后dispatch给reducer----->reducer接收并产生新的state----->state更新导致界面显示的刷新

2.fish_redux实战,接入网络,刷新等等实际应用场景

2.1 创建应用的根Widget

新建一个app.dart用来创建应用的根Widget,app.dart如下:

import 'package:fish_redux/fish_redux.dart';
import 'package:flutter_redux_demo/home/page.dart';
import 'package:flutter_redux_demo/login/page.dart';

Widget createApp() {
  final AbstractRoutes routes = PageRoutes(
    pages: <String, Page<Object, dynamic>>{
      /// 注册登陆主页面
      "login": LoginPage(),
      "home": HomePage(),
    },
    visitor: (String path, Page<Object, dynamic> page) {
      /// AOP
      /// 页面可以有一些私有的 AOP 的增强, 但往往会有一些 AOP 是整个应用下,所有页面都会有的。
      /// 这些公共的通用 AOP ,通过遍历路由页面的形式统一加入。
      page.enhancer.append(
        /// View AOP
        viewMiddleware: <ViewMiddleware<dynamic>>[
          safetyView<dynamic>(),
        ],

        /// Adapter AOP
        adapterMiddleware: <AdapterMiddleware<dynamic>>[safetyAdapter<dynamic>()],

        /// Effect AOP
        effectMiddleware: [
         // _pageAnalyticsMiddleware<dynamic>(),
        ],

        /// Store AOP
        middleware: <Middleware<dynamic>>[
          //这块主要用到middleware的打印功能,监听Action在页面间的调整过程
          //logMiddleware<dynamic>(tag: page.runtimeType.toString()), //这块主要用到middleware的打印功能,监听Action在页面间的调整过程
        ],
      );
    },
  );

  return MaterialApp(
    title: 'fish_redux_demo',
    debugShowCheckedModeBanner: false,
    theme: ThemeData(
      primarySwatch: Colors.blue,
    ),
    home: routes.buildPage('login',null),
    onGenerateRoute: (RouteSettings settings) {
      return MaterialPageRoute<Object>(builder: (BuildContext context) {
        return routes.buildPage(settings.name, settings.arguments);
      });
    },
  );
}

2.2新建第一个fish_redux页面Login

首先打开AS,新建一个package命名为login,表示登录页面,然后利用插件FishReduxTemplate,弹出快速创建页面:


创建fish_redux的文件目录
创建page需要的依赖.png
2.2.1编写Login-Page.dart,zhuyao
import 'package:fish_redux/fish_redux.dart';

import 'effect.dart';
import 'state.dart';
import 'view.dart';

class LoginPage extends Page<LoginState, Map<String, dynamic>> {
  LoginPage()
      : super(
            initState: initState,
            effect: buildEffect(),
            view: buildView,
           );

}
2.2.2 编写Login-page-state.dart,对应page.dart里面的initState
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/cupertino.dart';

class LoginState implements Cloneable<LoginState> {
  TextEditingController userNameController;
  TextEditingController passwordController;

  @override
  LoginState clone() {
    return LoginState()
    ..userNameController = userNameController
      ..passwordController = passwordController;
  }
}

LoginState initState(Map<String, dynamic> args) {
  LoginState state = LoginState();
  state.userNameController = new TextEditingController();
  state.passwordController = new TextEditingController();
  return state;
}
2.2.3 编写Login-page-view.dart,对应page.dart里面的buildView
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';

import 'action.dart';
import 'state.dart';

Widget buildView(LoginState state, Dispatch dispatch, ViewService viewService) {
  return Scaffold(
    appBar: PreferredSize(
      preferredSize: Size.fromHeight(50.0),
      child: AppBar(
        automaticallyImplyLeading: false,
        centerTitle: true,
        elevation: 0,
        title: Text('登录'),
      ),
    ),
    body: GestureDetector(
      onTap: (){//键盘收起
        FocusScope.of(viewService.context).requestFocus(new FocusNode());
      },
      child: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            SizedBox(height: 100,),
            Text(
              "安全管控",
              style: TextStyle(
                fontSize: 30,
                fontWeight: FontWeight.bold,
              ),
              textAlign: TextAlign.center,
            ),
            SizedBox(height: 100,),
            Row(
              children: <Widget>[
                SizedBox(width: 50,),
                Expanded(
                  child: TextField(
                    controller: state.userNameController,
                    decoration: InputDecoration(
                      hintText: "用户名",
                    ),
                  ),
                ),
                SizedBox(width: 50,),
              ],
            ),
            SizedBox(height: 30,),
            Row(
              children: <Widget>[
                SizedBox(width: 50,),
                Expanded(
                  child: TextField(
                    controller: state.passwordController,
                    decoration: InputDecoration(
                      hintText: "密码",
                    ),
                    obscureText: true,
                  ),
                ),
                SizedBox(width: 50,),
              ],
            ),
            SizedBox(height: 50,),
            RaisedButton(
              color: Colors.blue,
              child: Text(
                '登录',
                style: TextStyle(
                  color: Colors.white,
                ),
              ),
              onPressed: (){
                if(state.userNameController.text.isNotEmpty){
                  if(state.passwordController.text.isNotEmpty){
                    dispatch(LoginActionCreator.onLogin());
                  }
                  else{
                    Fluttertoast.showToast(msg: '密码不能为空');
                  }
                }
                else{
                  Fluttertoast.showToast(msg: '账号不能为空');
                }
              },
            ),
          ],
        ),
      ),
    ),
  );
}
2.2.4 编写Login-page-effect.dart,对应page.dart里面的buildEffect
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/cupertino.dart' hide Action;
import 'package:flutter_redux_demo/network/netuntil.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'action.dart';
import 'state.dart';
import 'dart:convert';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';

Effect<LoginState> buildEffect() {
  return combineEffects(<Object, Effect<LoginState>>{
    LoginAction.login: _onLogin,
  });
}

void _onLogin(Action action, Context<LoginState> ctx) {
  Map<String, dynamic> params = {
    'username':ctx.state.userNameController.text,
    'pwd':generateMd5(ctx.state.passwordController.text),
  };
  //登录接口
  NetUtlis.login('/userright/loginVerify.do',params: params,success: (value){
    if(value == '1'){
      Fluttertoast.showToast(msg: '登录成功');
      Navigator.of(ctx.context).pushNamed('home');
    }
    else{
      Fluttertoast.showToast(msg: '登录失败');
    }

  });
}
//MD5转码
String generateMd5(String data) {
  var content = new Utf8Encoder().convert(data);
  var digest = md5.convert(content);
  // 这里其实就是 digest.toString()
  return hex.encode(digest.bytes);
}
2.2.5 编写Login-page-action.dart,对应effect.dart里面意图action
import 'package:fish_redux/fish_redux.dart';

enum LoginAction { login }

class LoginActionCreator {
  static Action onLogin() {
    return const Action(LoginAction.login);
  }
}

至此,登录页面逻辑基本完成,这里没有用到adapter,dependencies等等.我们进入home页面!

2.3 新建主界面Home,按照上面的插件步骤,建立命名home的package

2.3.1 编写Home-page.dart
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter_redux_demo/home/home_adapter/adapter.dart';

import 'effect.dart';
import 'state.dart';
import 'view.dart';

class HomePage extends Page<HomeState, Map<String, dynamic>> {
  HomePage()
      : super(
            initState: initState,
            effect: buildEffect(),
            view: buildView,
            dependencies: Dependencies<HomeState>(
                adapter: NoneConn<HomeState>() + HomeAdapter(),
                slots: <String, Dependent<HomeState>>{
                }),
            middleware: <Middleware<HomeState>>[
            ],);

}
2.3.2 编写Home-page-state.dart,对应page.dart的initState
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_redux_demo/network/handover_entity.dart';


class HomeState implements Cloneable<HomeState> {
  EasyRefreshController refreshController;
  List<HandoverDataModel> list;
  int page;
  @override
  HomeState clone() {
    return HomeState()
    ..list = list
    ..refreshController = refreshController
    ..page = page;
  }
}

HomeState initState(Map<String, dynamic> args) {
  HomeState homeState = HomeState();
  homeState.refreshController = new EasyRefreshController();
  homeState.list = new List();
  homeState.page = 1;
  return homeState;
}
2.3.3 编写Home-page.view.dart,对应page.dart里面的buildView
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';

import 'action.dart';
import 'state.dart';

Widget buildView(HomeState state, Dispatch dispatch, ViewService viewService) {
  final ListAdapter adapter = viewService.buildAdapter();
  return Scaffold(
    appBar: PreferredSize(
      preferredSize: Size.fromHeight(50.0),
      child: AppBar(
        automaticallyImplyLeading: false,
        centerTitle: true,
        elevation: 0,
        title: Text('值长日志'),
      ),
    ),
    body: SafeArea(
      child: EasyRefresh(
//        bottomBouncing: false,
//        topBouncing: false,
        header: ClassicalHeader(),
        footer: ClassicalFooter(
          enableInfiniteLoad: false,
        ),
        controller: state.refreshController,
        onRefresh: () async{
          dispatch(HomeActionCreator.onRefresh());
        },
        onLoad: () async{
          dispatch(HomeActionCreator.onLoad(state.page));
        },
        child: ListView.builder(
          itemBuilder: adapter.itemBuilder,
          itemCount: adapter.itemCount,
        ),
      ),
    ),
  );

}
2.3.4 编写Home-page-action.dart,对应view.datr里面用的action
import 'package:fish_redux/fish_redux.dart';

enum HomeAction { onLoad, onRefresh }

class HomeActionCreator {
  static Action onLoad(int page) {
    return  Action(HomeAction.onLoad,payload: page);
  }

  static Action onRefresh(){
    return  Action(HomeAction.onRefresh);
  }
}
2.3.5 编写Home-page-effect.dart,对应page.dart里面的buildEffect
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter_redux_demo/home/home_adapter/action.dart';
import 'package:flutter_redux_demo/network/handover_entity.dart';
import 'package:flutter_redux_demo/network/netuntil.dart';
import 'action.dart';
import 'state.dart';

Effect<HomeState> buildEffect() {
  return combineEffects(<Object, Effect<HomeState>>{
    Lifecycle.initState:_init,
    HomeAction.onLoad: _onLoad,
    HomeAction.onRefresh: _onRefresh,
  });
}

void _init(Action action, Context<HomeState> ctx){
  ctx.dispatch(HomeActionCreator.onRefresh());
}

void _onLoad(Action action, Context<HomeState> ctx) {
  int page = action.payload;
  println("onload$page");
  NetUtlis.get("/utdcjjb/fdjiaojiebanlog/list.do?filter={'gangweiCode_\$equal':'5'}&page=$page&rows=10&sidx=lrtime&sord=desc",success: (value){
    ctx.state.page += 1;
    HandoverEntity entity = HandoverEntity.fromJson(value);
    ctx.state.refreshController.finishLoad(noMore: entity.data.xList.length <10);
    ctx.dispatch(HandOverActionCreator.loadMoreData(entity.data.xList));
  },failure: (error){
    print(error);
  });
}

void _onRefresh(Action action,Context<HomeState> ctx){
  int page = 1;
  ctx.state.page = 1;
  NetUtlis.get("/utdcjjb/fdjiaojiebanlog/list.do?filter={'gangweiCode_\$equal':'5'}&page=$page&rows=10&sidx=lrtime&sord=desc",success: (value){
    ctx.state.page += 1;
    HandoverEntity entity = HandoverEntity.fromJson(value);
    ctx.state.refreshController.resetLoadState();
    ctx.state.refreshController.finishRefresh();
    ctx.dispatch(HandOverActionCreator.reloadData(entity.data.xList));
  },failure: (error){
    print(error);
  });
}
2.3.6 新建一个home_adapter的package,按照插件格式,生成文件目录,编写Home-adapter.dart,对应page.dart里面dependencies的adapter
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter_redux_demo/home/home_component/component.dart';
import 'package:flutter_redux_demo/home/home_component/state.dart';
import 'package:flutter_redux_demo/network/handover_entity.dart';

import 'reducer.dart';
import '../state.dart';

class HomeAdapter extends DynamicFlowAdapter<HomeState> {
  HomeAdapter()
      : super(
          pool: <String, Component<Object>>{
            'handover': HandOverComponent(),
          },
          connector: _HomeConnector(),
          reducer: buildReducer(),
        );
}

class _HomeConnector extends ConnOp<HomeState, List<ItemBean>> {
  @override
  List<ItemBean> get(HomeState state) {
    if(state.list?.isNotEmpty == true){
      return state.list.map<ItemBean>((m){
        HandOverState handOverState = new HandOverState();
        handOverState.handoverDataModel = m;
            return ItemBean("handover", handOverState);
      }).toList();
    }else{
      return<ItemBean>[];
    }

  }

  @override
  void set(HomeState state, List<ItemBean> items) {
    if(items.isNotEmpty == true){
      state.list = List<HandoverDataModel>.from(items.map((m){
        return m;
    }).toList());
  }else{
      state.list = new List();
    }
  }
}
2.3.7 编写adapter的的action.dart和reducer.dart,生命周期比较长
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter_redux_demo/network/handover_entity.dart';
enum HandOverAction { reloadData, loadMoreData }

class HandOverActionCreator {
  static Action reloadData(List<HandoverDataModel> list) {
    return Action(HandOverAction.reloadData,payload: list);
  }

  static Action loadMoreData(List<HandoverDataModel> list) {
    return Action(HandOverAction.loadMoreData,payload: list);
  }
}
import 'package:fish_redux/fish_redux.dart';
import 'action.dart';
import '../state.dart';

Reducer<HomeState> buildReducer() {
  return asReducer(
    <Object, Reducer<HomeState>>{
      HandOverAction.reloadData: _reloadData,
      HandOverAction.loadMoreData:_loadMoreData,
    },
  );
}
//更新数据
HomeState _reloadData(HomeState state, Action action) {
  final HomeState newState = state.clone();
//  newState.list.clear();
  newState.list = action.payload;
  return newState;
}

HomeState _loadMoreData(HomeState state, Action action){
  final HomeState newState = state.clone();
  newState.list.addAll(action.payload);
  return newState;
}
2.3.8 新建home_component的package,根据插件提示生成目录结构。编写Home-page-component.dart
import 'package:fish_redux/fish_redux.dart';

import 'effect.dart';
import 'state.dart';
import 'view.dart';

class HandOverComponent extends Component<HandOverState> {
  HandOverComponent()
      : super(
          view: buildView,
        );
}
2.3.9 编写Home-page-component-state.dart,保存item的数据
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter_redux_demo/network/handover_entity.dart';

class HandOverState implements Cloneable<HandOverState> {
  HandoverDataModel handoverDataModel;
  @override
  HandOverState clone() {
    return HandOverState()..handoverDataModel = handoverDataModel;
  }
}
2.3.10 因为目前component只有buildView,所以我们只需要编写Home-page-component-view.dart!如果item点击需要进入详情等,就需要编写effect,reducer,action等等
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
import 'package:flustars/flustars.dart';
import 'state.dart';

Widget buildView(HandOverState state, Dispatch dispatch, ViewService viewService) {
  return Container(
    margin: EdgeInsets.fromLTRB(8, 4, 8, 4),
    decoration: BoxDecoration(
      border: Border.all(
        color: Color(0xffe8ebf0),
        width: 1,
      ),
      color: Colors.white,
    ),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Padding(padding: EdgeInsets.only(top: 5)),
        Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(padding: EdgeInsets.only(left: 16),),
            Text(
              (TextUtil.isEmpty(state.handoverDataModel.zhiciFname)?"当前班" : state.handoverDataModel.zhiciFname) + '-' + state.handoverDataModel.banciFname,

              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
                color: Colors.black,
              ),
            ),
            Spacer(
              flex: 1,
            ),
            Text(
              state.handoverDataModel.statusconfirm == "1"
                  ? "已接班"
                  : "未接班",
              style: TextStyle(
                fontSize: 14,
                color: state.handoverDataModel.statusconfirm == "1"
                    ? Color(0xFF00CA8D)
                    : Color(0xFFFF9B26),
              ),
            ),
            Padding(padding: EdgeInsets.only(right: 16),),
          ],
        ),
        Padding(padding: EdgeInsets.only(top: 2)),
        Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(padding: EdgeInsets.only(left: 16),),
            Text(
              "当班值长 :" + state.handoverDataModel.dbpeople,
              style: TextStyle(
                fontSize: 14,
                color: Color(0xFF676767),
              ),
            ),
          ],
        ),
        Padding(padding: EdgeInsets.only(top: 2)),
        Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(padding: EdgeInsets.only(left: 16),),
            Text(
              "接班时间 :" + state.handoverDataModel.mdate +"  " +
                  state.handoverDataModel.jbtime,
              style: TextStyle(
                fontSize: 14,
                color: Color(0xFF676767),
              ),
            )
          ],
        ),
        Padding(padding: EdgeInsets.only(bottom: 5)),
      ],
    ),
  );
}

至此,Home的页面也编写完成,逻辑也串起来了!
让我们来看看预览画面

登录界面.png Home界面.png

3. fish_redux总结和参考资料

fish_redux中文文档

手把手入门Fish-Redux开发flutter

上一篇 下一篇

猜你喜欢

热点阅读