Loading...
墨滴

岛上码农@公众号同名

2021/11/20  阅读:26  主题:橙心

Flutter 也能玩 React 的 Redux?

前言

React 开发者都知道Redux 在开发大中型 Web 应用的重要性, Flutter 作为 React 的高仿者,连 setState 都搬过来了,自然也需要把 Redux 也搬过来——好东西要一起分享

image.png
image.png

Redux 简介

Redux 是一个单向数据流的状态管理架构,通过它能够简化应用开发、测试和维护。Flutter的 Redux 相关插件地址:

  • redux:Flutter 中需要的全部 Redux 组件,例如 StoreReducerMiddleware
  • flutter_redux:Flutter 专属的插件包,在 redux 基础上进行了封装,使得在 Flutter 中应用更为简便,例如 StoreProvider(为组件提供 Store的基础 Widget),StoreBuilder(从 StoreProvider 中接收 Store 的组件)和 StoreConnector(用于替换 StoreBuilder,可以将 Store 转换为一个 ViewModel 来构建组件树,一旦 Store 中的 State 改变了就可以重建 StoreConnector)。

Redux 中,通过 Store 存储了代表整个应用的状态对象 State。每一个应用事件(不管是用户发起的或外部驱动)都被认为是一个 ActionAction 通过 Reducer 进行调度,然后 Reducer 根据 Action 来更新 Store 中的状态。而一旦 Store 中的状态对象 State改变了,对应的视图 View 就会反映状态的变化。 image.png Redux 的最大特点就是可以将大部分组件进行解耦,使得 UI界面的刷新更容易。而且,核心的业务逻辑都在 Reducer 函数中。Reducer 接收一个 Action和当前的状态,然后返回一个新的状态对象。因此,使得单元测试更容易,我们只需要测试 Reducer 就可以测试状态业务逻辑对不对。

Redux 中间件

上面仅仅是 Redux 的第一印象,但是如果要进行异步操作,例如从接口加载数据怎么办?这个时候就需要引入新的组件,称之为中间件(Middleware)。

中间件就是在Reducer前处理 Action 的组件。它接收当前的状态对象和要被调度的Action,然后运行代码(如接口通讯,数据访问等)。最终,中间件可能继续使用原先的 Action,或一个不同的 Action,甚至什么都不做。有了中间件后,Redux 的流程图就变成了下面这样:

image.png
image.png

上代码

接下来以一个简单的记数应用为例,来演示 Redux 的基本应用。首先我们构建Redux 的三要素。

// counter_actions.dart,目前为空,后续可以增加业务代码
// 计数器增加
class CounterAddAction {}
//计数器减少
class CounterSubAction {}

//counter_state.dart
class CounterState {
  int count = 0;

  CounterState(this.count);
}

// counter_reducer.dart
CounterState counterReducer(CounterState state, dynamic action) {
  if (action.runtimeType == CounterAddAction) {
    return CounterState(state.count + 1);
  }

  if (action.runtimeType == CounterSubAction) {
    return CounterState(state.count - 1);
  }

  return state;
}

可以看到,核心业务都在 reducer 里面,reducer 根据 action 的类型更新state,然后返回新的state 对象。action 是一个动态类型,如果简单的操作也可以是枚举,但是如果要携带新的数据或业务逻辑(例如,我们可以每次点击可以改变增加或减少的数量)使用对象会更方便。

ReduxReducer 定义形式如下,即接收旧的 stateaction 参数,然后返回新的 state

typedef Reducer<State> = State Function(State state, dynamic action)

接下来是页面逻辑的实现了。页面逻辑有点类似。如果一个 Store 需要被下级组件使用,那么就要定义在上一级组件中。这里我们比较简单,直接定义在当前页面即可。关键的部分有以下部分:

  • build 的子组件使用 StoreProvider 包裹,以便共享 store
  • 需要监听store 变化的组件使用 StoreConnectorbuilder 构建,并且可以使用 converter 方法将 store 转成组件需要的数据(即将状态数据转成 ViewModel),这里只是简单地将计数值转为了 String。在 StoreConnector 方法中构建的组件,一旦状态对象发生改变后就会通知刷新。
  • 按钮事件:在按钮中执行状态对象的dispatch操作,以便调度对应的 reducer 完成状态更新。dispatch 方法定义如下,可以看到实际上 dispatch 是一组调度,这里只是调用了第一个方法,这意味着其实可以执行一系列的调度操作。
dynamic dispatch(dynamic action) {
  return _dispatchers[0](action);
}
class CounterPage extends StatelessWidget {
  CounterPage({Key? key}) : super(key: key);
  final store =
      Store<CounterState>(counterReducer, initialState: CounterState(0));
  @override
  Widget build(BuildContext context) {
    return StoreProvider(
      store: store,
      child: Scaffold(
        appBar: AppBar(
          title: Text('Redux Counter'),
        ),
        body: Center(
          child: StoreConnector<CounterState, String>(
            converter: (store) => store.state.count.toString(),
            builder: (context, count) {
              return Text(
                count,
                style: TextStyle(color: Colors.blue, fontSize: 30),
              );
            },
          ),
        ),
        floatingActionButton: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            FloatingActionButton(
                child: Icon(Icons.arrow_upward),
                onPressed: () {
                  store.dispatch(CounterAddAction());
                }),
            FloatingActionButton(
                backgroundColor: Colors.red,
                child: Icon(
                  Icons.arrow_downward,
                ),
                onPressed: () {
                  store.dispatch(CounterSubAction());
                }),
          ],
        ),
      ),
    );
  }
}

运行效果

运行效果如下所示。 屏幕录制2021-08-21 下午1.59.54.gif

总结

本篇介绍了 Redux 的基本概念和一个简单的示例,通常来说,使用Redux 的一大好处是整个状态管理的业务模式都是一致的,都必须具备 ActionStoreReducer 这三个环节,这样其实也能够间接规范代码结构。同时,有了 flutter_redux 插件的适配,在 Flutter 中使用Redux也更为简便。 欢迎关注岛上码农

岛上码农@公众号同名

2021/11/20  阅读:26  主题:橙心

作者介绍

岛上码农@公众号同名