Flutter | 状态管理探索篇——Redux(二)

栏目: 服务器 · 发布时间: 7年前

内容简介:Flutter的很多灵感来自于React,它的设计思想是数据与视图分离,由数据映射渲染视图。所以在Flutter中,它的Widget是immutable的,而它的动态部分全部放到了状态(State)中。于是状态管理自然便成了我们密切关注的对象。在之前我们已经讨论了关于在flutter中这个系列将会从这几个状态管理方案进行深入研究:

Flutter的很多灵感来自于React,它的设计思想是数据与视图分离,由数据映射渲染视图。所以在Flutter中,它的Widget是immutable的,而它的动态部分全部放到了状态(State)中。于是状态管理自然便成了我们密切关注的对象。

在之前我们已经讨论了关于在flutter中 使用 scoped_model 进行状态管理 的应用。文章发出后,有许多同学都在问我,到底redux和scoped到底谁更好。

这个系列将会从这几个状态管理方案进行深入研究:

  • Scoped_model
  • redux
  • BLoC
  • 对比总结篇

所以今天要和大家介绍的是在flutter中使用Redux进行状态管理。 我希望各位在阅读这篇文章之前,先仔细思考以下这几个问题。

  • 什么是redux
  • redux给我们了什么好处,我们为什么要使用它
  • 它的基本思想是什么
  • redux是否真的适合我们

ok,我们开始正式的介绍redux。

Redux

为什么需要状态管理

在我们一开始构建应用的时候,也许很简单。我们有一些状态,直接把他们映射成视图就可以了。这种简单应用可能并不需要状态管理。

Flutter | 状态管理探索篇——Redux(二)

但是随着功能的增加,你的应用程序将会有几十个甚至上百个状态。这个时候你的应用应该会是这样。

Flutter | 状态管理探索篇——Redux(二)

Wow,这是什么鬼。我们很难再清楚的测试维护我们的状态,因为它看上去实在是太复杂了!而且还会有多个页面共享同一个状态,例如当你进入一个文章点赞,退出到外部缩略展示的时候,外部也需要显示点赞数,这时候就需要同步这两个状态。

这时候,我们便迫切的需要一个架构来帮助我们理清这些关系,状态管理框架应运而生。

redux是什么

Redux是一种 单向数据流 架构,可以轻松开发,维护和测试应用程序。

Flutter | 状态管理探索篇——Redux(二)
  • 我们在Redux中,所有的状态都储存在 Store 里。这个 Store 会放在App顶层。
  • View 拿到Store储存的状态(State)并把它映射成视图。View还会与用户进行交互,用户点击按钮滑动屏幕等等,这时会因为交互需要数据发生改变。
  • Redux让我们不能让View直接操作数据,而是通过发起一个 action 来告诉 Reducer ,状态得改变啦。
  • 这时候 Reducer 接收到了这个 action ,他就回去遍历action表,然后找到那个匹配的action,根据action 生成新的状态 并把新的状态放到Store中。
  • Store丢弃了老的状态对象,储存了新的状态对象后,就通知所有使用到了这个状态的View更新(类似setState)。这样我们就能够同步不同view中的状态了。

Lets do it!

这里我们以一个最简单的CountApp举例。简单介绍flutter_redux/redux的用法。该项目完整代码已上传 Github

这是一个在不同页面使用Redux共享状态信息的app。这两个页面都依赖于一个数字,这个数字会随着我们按下按钮的次数而增加。

Flutter | 状态管理探索篇——Redux(二)

第一步:添加依赖

Flutter | 状态管理探索篇——Redux(二)

我们这里使用了redux/flutter_redux库,它们都是由Brian Egan大神编写的。其中flutter_redux是用来简化redux的使用的。

第二步:创建State

我们刚才介绍了Redux的流程,状态是由 reducer生成并储存在Store 里面的。Store更新状态的时候,并 不是更改原来的状态对象 ,而是直接将reducer生成的新的状态对象 替换 掉老的状态对象。所以,我们的状态应该是immutable的。

import 'package:meta/meta.dart';
/**
 * State中所有属性都应该是只读的
 */
@immutable
class CountState{
  int _count;
  get count => _count;

  CountState(this._count);
}
复制代码

第三步:创建action

可能各位最开始接触的时候对Action还会摸不着头脑。action到底是什么?View如何发出action。其实,action只是我们对状态进行操作方法的一个代号而已。在我们这个应用中,唯一的一个功能就是让count的值+1,所以我们这里只有一个action。

/**
 * 定义操作该State的全部Action
 * 这里只有增加count一个动作
 */
enum Action{
  increment
}
复制代码

第四步:创建reducer

reducer是我们的状态生成器,它接收一个我们原来的状态,然后接收一个action,再匹配这个action生成一个新的状态。

/**
 * reducer会根据传进来的action生成新的CountState
 */
CountState reducer(CountState state,action){
  //匹配Action
    if(action == Action.increment){
      return CountState(state.count+1);
    }
    return state;
}
复制代码

第五步:创建store

Store接收一个reducer,以及初始化State,我们想用Redux管理全局的状态的话,需要将store储存在应用的入口才行。而在应用打开时要先初始化一次应用的状态。所以在State中添加一个初始化的函数。

//这段代码写在State中
CountState.initState(){ _count = 0;}
复制代码
//应用顶层
void main() {
  final store =
      Store<CountState>(reducer, initialState: CountState.initState());
  runApp(new MyApp(store));
}
复制代码

第六步:将Store放入顶层

flutter_redux提供了一个很棒的widget叫做StoreProvider,它的用法也很简单,接收一个store,和child Widget。

class MyApp extends StatelessWidget {
  final Store<CountState> store;

  MyApp(this.store);

  @override
  Widget build(BuildContext context) {
    return StoreProvider<CountState>(
      store: store,
      child: new MaterialApp(
        title: 'Flutter Demo',
        theme: new ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: TopScreen(),
      ),
    );
  }
}
复制代码

第六步:在子页面中获取Store中的state

这里建议大家把实际代码对照下面的解释一起看。

StoreConnector<CountState,int>(
              converter: (store) => store.state.count,
              builder: (context, count) {
                return Text(
                  count.toString(),
                  style: Theme.of(context).textTheme.display1,
                );
              },
            ),
复制代码

要想获取store我们需要使用StoreConnector<S,ViewModel>。StoreConnector能够通过StoreProvider找到顶层的store。而且能够在state发生变化时rebuilt Widget。

Flutter | 状态管理探索篇——Redux(二)
  • 首先这里需要 强制声明类型 ,S代表我们需要从store中获取什么类型的state,ViewModel指的是我们使用这个State时的实际类型。
  • 然后我们需要声明一个 converter<S,ViewModel> ,它的作用是将Store转化成实际ViewModel将要使用的信息,比如我们这里实际上要使用的是count,所以这里将count提取出来。
  • builder 是我们实际根据state创建Widget的地方,它接收一个上下文context,以及刚才我们转化出来的ViewModel,所以我们就只需要把拿到的count放进Text Widget中进行渲染就好了。

第七步:发出action

我们这个应用在第二个页面中,通过点击floatingActionButton发出了action,并通知reducer生成了新的状态。

floatingActionButton: StoreConnector<CountState,VoidCallback>(
        converter: (store) {
          return () => store.dispatch(Action.increment);
        },
        builder: (context, callback) {
          return FloatingActionButton(
            onPressed: callback,
            child: Icon(Icons.add),
          );
        },
      ),
复制代码
  • 同样,我们还是使用StoreConnector<S,ViewModel>。这里由于是发出了一个动作,所以是VoidCallback。
  • store.dispatch发起一个action,任何中间件都会拦截该操作,在运行中间件后,操作将被发送到给定的 reducer 生成新的状态,并更新状态树。

以上便是在flutter中使用redux共享状态信息的全部内容。

Q&A

ViewModel性能优化

我们的StoreConnector能够将store提取出信息并转化成ViewModel,这里其实是有一个性能优化的点的。我们这里的例子非常简单,它的ViewModel就只是一个int的值,当我们ViewModel很复杂的时候,我们可以使用StoreConnector的distinct属性进行性能优化。使用方法很简单:需要我们在ViewModel中重写[==] and [hashCode] 方法,然后把distinct属性设为true。

如何处理异步数据

Redux提供了一种简单的方法来更新应用程序的状态以响应同步操作。但是,它缺少处理异步代码的工具。我们如何应对异步相应呢。

这里就需要一个interrupt来处理异步请求,然后再发出新的action通知reducer生成新的State了。 这里有brianegan大神写的另外一个帮助在flutter中使用redux处理异步请求的库redux_thunk。我会在之后的文章中详细介绍如何在redux中处理异步操作。

你认为redux真的适合flutter吗

我们发现,redux的确能够在flutter中很好的工作。在react中数据是没有上行能力的,所以通过数据单向流动形成一个环来进行状态管理。看上去似乎并没有把flutter中的优势完全发挥出来。在这个简单的例子中我们也可以看出,使用redux还是 稍微有些麻烦的 ,用的不好,可能会陷入redux地狱。学习成本偏高也是它的一大痛点。

当然,redux这套状态管理架构已经比较成熟,假如您已经习惯redux,也能够快速通过flutter_redux轻松构建属于您的状态管理应用。

那么你现在如何看待redux呢?

写在最后

本次所用到的代码已经上传Github: github.com/Vadaski/Flu…

这篇文章参考了以下资料

了解更多

你能在这些地方了解更多关于flutter-redux

如果您对flutter_redux还有任何看法或者文章的建议或者文章中有任何不对之处,欢迎在下方评论区以及我的邮箱1652219550a@gmail.com留言,我会在24小时内与您联系!

按理说下一章我们将探索BLoC在Flutter中的实践,而BLoC非常Reactive Programming,所以我决定先让大家了解一些dart:Stream的知识再介绍它,所以下一篇文章我们会介绍Stream以及流式编程,敬请关注。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Fluent Python

Fluent Python

Luciano Ramalho / O'Reilly Media / 2015-8-20 / USD 39.99

Learn how to write idiomatic, effective Python code by leveraging its best features. Python's simplicity quickly lets you become productive with it, but this often means you aren’t using everything th......一起来看看 《Fluent Python》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器