美文网首页flutter
Flutter状态管理(五):Redux

Flutter状态管理(五):Redux

作者: 青叶小小 | 来源:发表于2021-01-29 10:49 被阅读0次

一、前言

Flutter状态管理系列:
Flutter状态管理(一):ScopedModel
Flutter状态管理(二):Provider
Flutter状态管理(三):BLoC(Business Logic Component)
Flutter状态管理(四):ReactiveX之RxDart
Flutter状态管理(五):Redux

二、Redux介绍

有做过H5前端开发的朋友应该很早就接触过这个,Redux在React/VUE中,与在Flutter/Dart中概念一样,没有任何区别;唯一的区别只是使用上的不同。

一句话来介绍Redux:Redux是前端流行的,一种单向(unidirectional)数据流架构!

它主要由三部分组成:

  • Store: 它是整个数据的仓库,存储State对象,管理着整个应用的状态;
  • Reducer:处理与分发事件的方法,通过返回新的State来更新Store;
  • Action: 行为(也可以理解为事件),action将会分发至对应的reducer中;

下图是一个完整的数据触发及更新流程:

  1. View产生Action(传递事件类型及数据);
  2. Redux将Action 派发(dispatch)至对应的 Reducer;
  3. Reducer根据Action的类型,处理完后返回一个全新的 State 至 Store;
  4. Store收到新的State后将来通知相应的监听者(View)更新;
redux.png

我们看到上面整个数据流,都是单向的,由View发起,最后到View的更新;

为啥这样设计?

  • 单一数据源:整个应用的状态都在一个Store中;
  • 状态只读: 无法直接修改Store中的数据,只能通过action -> reducer来完成;
  • 纯函数改变:reducer就是一个纯函数,只处理逻辑并返回全新的State;

三、Redux之Middleware

小节二介绍了Redux最基本的原理,但是,如何用Redux来做一些异步操作,比如:加载数据、请求API等?这里就引出来了Redux的中间件(Middleware),中间件能够让我们使得action在到达reducer之前,做些其它“动作”!有了中间件,我们不但可以请求API,还可以改变action,使得分发到其它reducer中去;

midware.png

上图是有Middleware的流程图。

四、引入Redux相关的第三方库

// pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

  redux: ^4.0.0+3
  flutter_redux: ^0.6.0
  • redux:基础库,包含了Store、Reducer和Middleware;
  • flutter_redux:用于Flutter的封装好的库(类似React中的react-redux):
    • StoreProvider:用于整个APP顶层,提供给所有的Widgets所需的Store;
    • StoreBuilder: 接收Store的变化通知;
    • StoreConnector:可替代StoreBuilder,能够将Store转成ViewModel;

五、Redux使用方式

Redux在Flutter中的使用与在JavaScript中的使用方式稍微有点不同,为啥?
因为JavaScript是弱类型语言,而Dart是强类型语言,这就使得在JS中每个reducer可以独立管理,而在Flutter中需要由一个大对象来管理!

5.1、目录结构

无论在JS中还是在Flutter中,通常都将action、reducer、store各自建一目录,放在redux目录下,目录结构如下:

.src
 |-- pages/
 |-- redux/
       |-- actions/
             |-- XxxAction.dart
             |-- YyyAction.dart
       |-- reducers/
             |-- XxxReducer.dart
             |-- YyyReducer.dart
            |-- index.dart      // App整个的reducers
       |-- states/              //(Flutter中需要,JS不需要)
            |-- XxxState.dart
            |-- YyyState.dart
            |-- index.dart      // App整个的状态对象
       |-- store/
            |-- index.dart      // App整个的store
 |-- main.dart

5.2、创建Action

// CountAction.dart
class SetCountAction {
  final int value;
  SetCountAction(this.value);
}
class IncrementCountAction {}
class DecrementCountAction {}
// FirstAction.dart
class SetFirstAction {
  final String value;
  SetFirstAction(this.value);
}

5.3、创建State

// CountState.dart
class CountState {
  final int count;
  CountState(this.count);
}
// FirstState.dart
class FirstState {
  String title;
  FirstState(this.title);
}
// index.dart (App整个的State大对象)
import 'package:stateresearch/redux/states/CountState.dart';
import 'package:stateresearch/redux/states/FirstState.dart';

class AppState {
  final FirstState firstState;
  final CountState countState;
  AppState(this.firstState, this.countState);
}

5.4、创建Reducer

// CountReducer.dart
import 'package:redux/redux.dart';
import 'package:stateresearch/redux/actions/CountAction.dart';
import 'package:stateresearch/redux/states/CountState.dart';

// 以下用两种方式创建 reducer
// 1. 基本的 switch-case
// 2. 使用 combineReducers + TypedReducer

//CountState countReducer(state, action) {
//  switch (action.runtimeType) {
//    case IncrementCountAction:
//      return CountState(state.count + 1);
//
//    case DecrementCountAction:
//      return CountState(state.count - 1);
//
//    case SetCountAction:
//      return CountState((action as SetCountAction).value);
//
//    default:
//      return state;
//  }
//}

// 使用 combineReducers 避免写 switch-case
// TypedReducer 的作用就是将 Function 与 Action 关联
final countReducer = combineReducers<CountState>([
  TypedReducer<CountState, IncrementCountAction>(_increment),
  TypedReducer<CountState, DecrementCountAction>(_decrement),
  TypedReducer<CountState, SetCountAction>(_set),
]);

CountState _increment(state, action) => CountState(state.count + 1);
CountState _decrement(state, action) => CountState(state.count - 1);
CountState _set(state, SetCountAction action) => CountState(action.value);
// FirstReducer
import 'package:stateresearch/redux/actions/FirstAction.dart';
import 'package:stateresearch/redux/states/FirstState.dart';

FirstState firstReducer(state, action) {
  switch (action.runtimeType) {
    case SetFirstAction:
      return FirstState((action as SetFirstAction).value);
    default:
      return state;
  }
}
// index.dart
import 'package:stateresearch/redux/reducers/CountReducer.dart';
import 'package:stateresearch/redux/reducers/FirstReducer.dart';
import 'package:stateresearch/redux/states/index.dart';

AppState reducers(AppState state, action) {
  return AppState(
    firstReducer(state.firstState, action),
    countReducer(state.countState, action),
  );
}

5.5、创建Store

// index.dart
import 'package:redux/redux.dart';
import 'package:stateresearch/redux/reducers/index.dart';
import 'package:stateresearch/redux/states/CountState.dart';
import 'package:stateresearch/redux/states/FirstState.dart';
import 'package:stateresearch/redux/states/index.dart';

final store = Store<AppState>(
  reducers,
  initialState: AppState(
    FirstState(null),
    CountState(0),
  ),
);

5.6、新建两个页面(ReduxPage和ReduxPage2)

ReduxPage在build中,也可以直接用StoreBuilder(参考ReduxPage2中写法),因为StoreBuilder也是InheritedWidget。

// ReduxPage.dart
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:stateresearch/pages/ReduxPage2.dart';
import 'package:stateresearch/redux/actions/CountAction.dart';
import 'package:stateresearch/redux/actions/FirstAction.dart';
import 'package:stateresearch/redux/states/CountState.dart';
import 'package:stateresearch/redux/states/index.dart';

class ReduxPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return _body(context);
  }

  Widget _body(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("ReduxPage")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('You have pushed the button this many times:'),
            StoreConnector<AppState, CountState>(
              converter: (store) {
                return store.state.countState;
              },
              builder: (context, state) {
                return Text("${state.count}");
              },
            )
          ],
        ),
      ),
      floatingActionButton: StoreBuilder<AppState>(
        builder: (context, store) {
          return Row(
            children: [
              FloatingActionButton(
                onPressed: () => store.dispatch(IncrementCountAction()),
                tooltip: 'Increment',
                child: Icon(Icons.add),
                heroTag: 'Increment',
              ),
              FloatingActionButton(
                onPressed: () => store.dispatch(DecrementCountAction()),
                tooltip: 'Decrement',
                child: Icon(Icons.close),
                heroTag: 'Decrement',
              ),
              FloatingActionButton(
                onPressed: () => store.dispatch(SetCountAction(100)),
                tooltip: 'Set',
                child: Icon(Icons.settings),
                heroTag: 'Set',
              ),
              FloatingActionButton(
                onPressed: () => store.dispatch(SetFirstAction("chris's age = ${Random().nextInt(100)}")),
                tooltip: 'First',
                child: Icon(Icons.event),
                heroTag: 'First',
              ),
              FloatingActionButton(
                onPressed: () {
                  Navigator.of(context).push(MaterialPageRoute(builder: (context) {
                    return ReduxPage2();
                  }));
                },
                tooltip: 'NextPage',
                child: Icon(Icons.message),
                heroTag: 'NextPage',
              )
            ],
          );
        },
      ),
    );
  }
}
// ReduxPage2.dart
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:stateresearch/redux/states/index.dart';

class ReduxPage2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return _body(context);
  }

  Widget _body(BuildContext context) {
    return StoreBuilder<AppState>(
      builder: (context, store) => Scaffold(
        appBar: AppBar(
          title: Text("${store.state.firstState.title}"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('You have pushed the button this many times:'),
              Text("${store.state.countState.count}")
            ],
          ),
        ),
      ),
    );
  }
}

5.7、修改main文件

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:stateresearch/pages/ReduxPage.dart';
import 'package:stateresearch/redux/states/index.dart';
import 'package:stateresearch/redux/store/index.dart';

void main() {
  runApp(StoreProvider<AppState>(store: store, child: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter状态管理',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: ReduxPage(),
    );
  }
}

六、总结

正因为Redux在Flutter中与在JS中不同,因此,在Flutter中,建议:

  • 如果只是局部使用,不涉及到跨 widget / page 共享,那么最好不要使用 Redux;
  • 相反,Redux 只放全局共享数据 (毕竟是大对象);

相关文章

  • Flutter状态管理(五):Redux

    一、前言 Flutter状态管理系列:Flutter状态管理(一):ScopedModel[https://www...

  • Flutter redux 使用与理解

    Flutter 状态管理redux 方案理解与实践 redux 数据管理方式来自 react ,React 的数据...

  • flutter redux的理解

    redux是 flutter项目中的 状态管理解决方案redux[https://pub.dev/packages...

  • Flutter状态管理

    Flutter状态管理ScopedModel 垃圾Redux 咸鱼的 太大bloc 也还行StatefulWidg...

  • Flutter Redux 状态管理

    Xmpp中经常遇到消息刷新,红点刷新,等问题. 消息到处发送,代码也不利于维护,发现有个redux,方便好用,记录...

  • Flutter状态管理之路(五)

    接上一篇Flutter状态管理之路(四)此篇主要介绍flutter_mobx Fish Redux 版本:0.2....

  • Flutter之状态管理

    Flutter的状态管理有:1、State:Flutter自带的,开发耦合度高,不推荐2、fish_redux:阿...

  • Redux

    Redux状态管理 Redux 是 JavaScript 状态管理容器,提供可预测的状态管理。redux 可以让你...

  • Flutter状态管理之redux

  • Flutter状态管理之Redux

    当你开发flutter到一定阶段的时候你就会发现,在这个一切皆组件的项目中,同时也会是一切皆状态,好几十个状态满天...

网友评论

    本文标题:Flutter状态管理(五):Redux

    本文链接:https://www.haomeiwen.com/subject/naqqtltx.html