Flutter之状态管理(Redux)flutter_redux

Flutter是Google(全球顶级互联网科技公司)出品,后台够硬,毫无疑问Flutter即将或已经成为跨平台开发的主流,Flutter野心很大,不仅冲击着原生开发,而且很有可能会烧到Web前端。作为移动端开发者的你,如果不关注Flutter的话,实在说不过去啦!

Flutter状态管理(Redux)flutter_redux的应用

什么时候不需要Redux,什么时候需要Redux

如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。
1.用户的使用方式非常简单
2.用户之间没有协作
3.不需要与服务器大量交互,也没有使用 WebSocket
4.视图层(View)只从单一来源获取数据
上面这些情况,都不需要使用 Redux。

1.用户的使用方式复杂
2.不同身份的用户有不同的使用方式(比如普通用户和管理员)
3.多个用户之间可以协作
4.与服务器大量交互
5.View要从多个来源获取数据
上面这些情况才是 Redux 的适用场景:多交互、多数据源。

从组件角度看,如果你的应用有以下场景,可以考虑使用 Redux。
1.某个组件的状态,需要共享
2.某个状态需要在任何地方都可以拿到
3.一个组件需要改变全局状态
4.一个组件需要改变另一个组件的状态

发生上面情况时,如果不使用 Redux 或者其他状态管理工具,不按照一定规律处理状态的读写,代码很快就会变成一团乱麻。你需要一种机制,可以在同一个地方查询状态、改变状态、传播状态的变化。
总之,不要把 Redux 当作万灵丹,如果你的应用没那么复杂,就没必要用它。另一方面,Redux 只是 状态管理的一种解决方案,也可以选择其他方案。
如:Provider

一、效果图

界面初始化状态
Flutter之状态管理(Redux)flutter_redux_第1张图片

点击按钮发起一个Redux Action更新界面(即更新State)
Flutter之状态管理(Redux)flutter_redux_第2张图片

Redux 的工作流程
Flutter之状态管理(Redux)flutter_redux_第3张图片

2、Flutter中集成flutter_redux

在pubspec.yaml文件中添加flutter_redux,当前版本1.1.0:

flutter_redux: ^0.5.3

2、创建用户实体


class User{
  var name;
  User(this.name);

  void setName(String name) {
    this.name = name;
  }

  String get getName => this.name;

  // 命名构造函数
  User.empty();
}

3、创建State(YDCState)

(1) Store对象包含所有数据。如果想得到某个时点的数据,就要对 Store 生成快照。这种时点的数据集合,就叫做 State。
(2) Redux 规定, 一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然。


import 'package:ydcflutter_app/test/bean/User.dart';
import 'package:ydcflutter_app/redux/user_redux.dart';
///全局Redux store 的对象,保存State数据
class YDCState {
  ///用户信息
  User user;

  ///构造方法
  YDCState({this.user});
}

4、创建Action

(1) State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。
(2) Action 描述当前发生的事情。改变 State 的唯一办法,就是使用 Action。它会运送数据到 Store。

/// 如果有 UpdateUserAction 发起一个请求时
/// 就会调用到 _updateLoaded
/// _updateLoaded 这里接受一个新的userInfo,并返回
User _updateLoaded(User user, action) {
  user = action.user;
  return user;
}

///定一个 UpdateUserAction ,用于发起 userInfo 的的改变
///类名随你喜欢定义,只要通过上面TypedReducer绑定就好
class UpdateUserAction {
  final User user;

  UpdateUserAction(this.user);
}

5、创建reducer

(1) Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。
(2) redux 的 combineReducers, 通过 TypedReducer 将 UpdateUserAction 与 reducers 关联起来
(3) Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。

///创建 Reducer
///源码中 Reducer 是一个方法 typedef State Reducer(State state, dynamic action);
///我们自定义了 appReducer 用于创建 store
YDCState appReducer(YDCState state, action) {
  return YDCState(
    ///通过自定义 UserReducer 将 YDCState 内的 userInfo 和 action 关联在一起
    user: UserReducer(state.user, action),

  );
}
final UserReducer = combineReducers([
  TypedReducer(_updateLoaded),
]);

以上几个步骤代码都在YDCState和user_redux.dart中

YDCState代码如下:

import 'package:ydcflutter_app/test/bean/User.dart';
import 'package:ydcflutter_app/redux/user_redux.dart';
///全局Redux store 的对象,保存State数据
class YDCState {
  ///用户信息
  User user;

  ///构造方法
  YDCState({this.user});
}

///创建 Reducer
///源码中 Reducer 是一个方法 typedef State Reducer(State state, dynamic action);
///我们自定义了 appReducer 用于创建 store
YDCState appReducer(YDCState state, action) {
  return YDCState(
    ///通过自定义 UserReducer 将 YDCState 内的 userInfo 和 action 关联在一起
    user: UserReducer(state.user, action),

  );
}

user_redux.dart代码如下:

import 'package:redux/redux.dart';
import 'package:ydcflutter_app/test/bean/User.dart';
/**
 * 用户相关Redux
 */

/// redux 的 combineReducers, 通过 TypedReducer 将 UpdateUserAction 与 reducers 关联起来
final UserReducer = combineReducers([
  TypedReducer(_updateLoaded),
]);


/// 如果有 UpdateUserAction 发起一个请求时
/// 就会调用到 _updateLoaded
/// _updateLoaded 这里接受一个新的userInfo,并返回
User _updateLoaded(User user, action) {
  user = action.user;
  return user;
}

///定一个 UpdateUserAction ,用于发起 userInfo 的的改变
///类名随你喜欢定义,只要通过上面TypedReducer绑定就好
class UpdateUserAction {
  final User user;

  UpdateUserAction(this.user);
}

6、创建store
(1 ) Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。
(2) Store接收一个reducer,以及初始化State,我们想用Redux管理全局的状态的话,需要将store储存在应用的入口才行。而在应用打开时要先初始化一次应用的状态。所以在State中添加一个初始化的函数。

 /// 创建Store,引用 YDCState 中的 appReducer 创建 Reducer
  /// initialState 初始化 State
  final store = new Store(
    appReducer,
    initialState: new YDCState(
        user: User(""),

  ));

7、将Store放入顶层

flutter_redux提供了一个很棒的widget叫做StoreProvider,它的用法也很简单,接收一个store,和child Widget。
Flutter之状态管理(Redux)flutter_redux_第4张图片
main文件全部源码:

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:ydcflutter_app/login/LoginPage.dart';

import 'package:ydcflutter_app/common/test/CartModel.dart';
import 'package:ydcflutter_app/common/test/Item.dart';
import 'package:provider/provider.dart';
import 'package:ydcflutter_app/test/bean/YDCState.dart';
import 'package:ydcflutter_app/test/bean/User.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';

//
//void main() => runApp( ChangeNotifierProvider.value(
//    value: new CartModel("格子衬衫"),
//    child:new YDCApp()));


void main() => runApp( new YDCApp());

final ThemeData kIOSTheme = new ThemeData(
  primarySwatch: Colors.orange,
  primaryColor: Colors.grey[100],
  primaryColorBrightness: Brightness.light,
);

final ThemeData kDefaultTheme = new ThemeData(
  primarySwatch: Colors.purple,
  accentColor: Colors.orangeAccent[400],
);

class YDCApp  extends StatelessWidget {
  /// 创建Store,引用 YDCState 中的 appReducer 创建 Reducer
  /// initialState 初始化 State
  final store = new Store(
    appReducer,
    initialState: new YDCState(
        user: User(""),

  ));
  YDCApp({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    /// 通过 StoreProvider Widget 应用 store
    return new StoreProvider(
        store: store,
        child:new MaterialApp(
//      title: '谈天说地',
//      theme: defaultTargetPlatform == TargetPlatform.iOS
//          ? kIOSTheme
//          : kDefaultTheme,
      theme: new ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: Colors.grey[50],
        scaffoldBackgroundColor: Colors.grey[50],
        dialogBackgroundColor: Colors.grey[50],
        primaryColorBrightness: Brightness.light,
        buttonColor: Colors.blue,
        iconTheme: new IconThemeData(
          color: Colors.grey[700],
        ),
        hintColor: Colors.grey[400],
      ),
      title: '纸聊',

//      supportedLocales: [
//        const Locale('zh', 'CH'),
//        const Locale('en', 'US'),
//      ],

      home:  new LoginPage(),
    ));
  }
}

8、在子页面中获取Store中的state

通过StoreConnector获取store,S代表我们需要从store中获取什么类型的state,ViewModel指的是我们使用这个State时的实际类型。此时能够监听state发生变化时rebuilt Widget。


  @override
  Widget build(BuildContext context) {
    ///通过 StoreConnector 关联 YDCState 中的 User
    return new StoreConnector(
      ///通过 converter 将 YDCState 中的 userInfo返回
      converter: (store) => store.state.user,
      ///在 userInfo 中返回实际渲染的控件
      builder: (context, userInfo) {
        return new Scaffold( body:Center(
          child: Builder(builder: (context) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Builder(builder: (context) {
                  return Text("使用Redux更新数据: ${userInfo.name}");
                }),

            new Padding(
            padding: const EdgeInsets.only(top: 15.0),
                child:
                StoreConnector(
                  converter: (store) {

                    var newUserInfo=User("把用户名字更新为无用");
                    return () => store.dispatch(new UpdateUserAction(newUserInfo));
                  },
                  builder: (context, callback) {
                    return FloatingActionButton(
                      onPressed: callback,
                      child: Icon(Icons.add),
                    );
                  },
                )
            ),

              ],
            );
          }),
        ),
        );
      },
    );
     }

9、使用 store.dispatch发出action

store.dispatch()是 View 发出 Action 的唯一方法。

 new Padding(
            padding: const EdgeInsets.only(top: 15.0),
                child:
                StoreConnector(
                  converter: (store) {

                    var newUserInfo=User("把用户名字更新为无用");
                    return () => store.dispatch(new UpdateUserAction(newUserInfo));
                  },
                  builder: (context, callback) {
                    return FloatingActionButton(
                      onPressed: callback,
                      child: Icon(Icons.add),
                    );
                  },
                )
            ),

store.dispatch接受一个 Action 对象作为参数,将它发送出去。

TestReduxPage全部代码:

import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:ydcflutter_app/redux/user_redux.dart';
import 'package:ydcflutter_app/test/bean/User.dart';
import 'package:ydcflutter_app/test/bean/YDCState.dart';

class TestReduxPage extends StatefulWidget {
  @override
  State createState() => new _TestReduxPageState();
}

class _TestReduxPageState extends State {

  BuildContext mContext;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    ///通过 StoreConnector 关联 YDCState 中的 User
    return new StoreConnector(
      ///通过 converter 将 YDCState 中的 userInfo返回
      converter: (store) => store.state.user,
      ///在 userInfo 中返回实际渲染的控件
      builder: (context, userInfo) {
        return new Scaffold( body:Center(
          child: Builder(builder: (context) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Builder(builder: (context) {
                  return Text("使用Redux更新数据: ${userInfo.name}");
                }),

            new Padding(
            padding: const EdgeInsets.only(top: 15.0),
                child:
                StoreConnector(
                  converter: (store) {

                    var newUserInfo=User("把用户名字更新为无用");
                    return () => store.dispatch(new UpdateUserAction(newUserInfo));
                  },
                  builder: (context, callback) {
                    return FloatingActionButton(
                      onPressed: callback,
                      child: Icon(Icons.add),
                    );
                  },
                )
            ),

              ],
            );
          }),
        ),
        );
      },
    );
     }


  Widget dividerWidget = new Container(
    //margin: const EdgeInsets.only( left: 10.0,right: 10.0),
      child: new Padding(
          padding: const EdgeInsets.only(left: 0.0, right: 0.0),
          child:
          new Divider(height: 1.0, indent: 0.0, color: Color(0xFFe5e5e5))
      )

  );

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


也可以把上面的StoreConnector更换成使用 StoreBuilder 获取 store 中的state数据变化而刷新UI,效果是一样的而且使用起来更加方便些

import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:ydcflutter_app/redux/user_redux.dart';
import 'package:ydcflutter_app/test/bean/User.dart';
import 'package:ydcflutter_app/test/bean/YDCState.dart';


class TestReduxPage extends StatefulWidget {
  @override
  State createState() => new _TestReduxPageState();
}

class _TestReduxPageState extends State {

  BuildContext mContext;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    //使用 StoreBuilder 获取 store 中的state数据
    return  new StoreBuilder(
            builder: (context, store) {
              return new Scaffold(
                  body: Center(
                      child: Builder(builder: (context) {
                        return Column(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Builder(builder: (context) {
                                return Text("使用Redux更新数据: ${store.state.user.name??"---"}");
                              }),
                              new Padding(
                                  padding: const EdgeInsets.only(top: 15.0),
                                  child:
                                  new FloatingActionButton(
                                    onPressed: (){
                                      var newUserInfo=User("把用户名字更新为无用");
                                      store.dispatch(new UpdateUserAction(newUserInfo));
                                    },
                                    child: Icon(Icons.add),
                                  )
                              )
                            ]
                        );

                      }))
              );
            });
  }


  Widget dividerWidget = new Container(
    //margin: const EdgeInsets.only( left: 10.0,right: 10.0),
      child: new Padding(
          padding: const EdgeInsets.only(left: 0.0, right: 0.0),
          child:
          new Divider(height: 1.0, indent: 0.0, color: Color(0xFFe5e5e5))
      )

  );

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


Flutter商城项目实战:https://github.com/dechengyang/ydc_flutter_app

如果对你有帮助,随意赏我奶粉钱吧,多谢!

微信:
在这里插入图片描述
支付宝:
在这里插入图片描述

你可能感兴趣的:(Flutter)