flutter 一直loading_使用 redux 管理 flutter 应用数据

cadde4a37642d630c96615c1e4f0885d.png

本文发布在使用 redux 管理 flutter 应用数据,后续一直会更新,感兴趣的可以关注一下。

最近在学 flutter,边学边记录了一本 写给前端看的 flutter 笔记,感兴趣的小伙伴可以一起来完善他。


使用 redux 管理 flutter 应用数据

redux 是什么?简单来说,就是为了解决 UI 层状态管理的方案,如果不熟悉,请先看文档学习一下,今天的重点不是学习 redux,而是直接用 redux 管理 flutter 的状态。

和 react 的比较

首先,flutter 和 react 真的太像了,连状态管理都有 redux 方案:

| flutter | react |

| :--- | :-- |

| redux.dart | redux |

| flutter_redux | react-redux |

| redux_thunk | redux-thunk |

另外,甚至还有 redux-epics 能够搭配 rxdart 对标 redux-observable。对于 rxjs 熟悉的人应该也能够很快地开始 rxdart 了,再次证明知识是相似的,技能也是能够越学越快的。

为了不混淆大家,接下来我把 react 中的 redux 称为 react/redux, flutter 中的 redux 称为 flutter/redux

正题

现在我们用 flutter 写一个简单的 redux 例子:

bdba2e21efc5aa9112c8d022f4a79798.gif

完整代码在 https://github.com/riskers/flutter_notebook_redux ,有过 redux 经验的应该能看明白。使用到了:

  • redux
  • flutter_redux
  • redux_thunk
项目架构完全是之前按照我之前在 React 中的经验来做的

有几点需要注意:

  1. 初始化 Store

为了方便,可以在 state 中以一个静态方法初始化:

  static AppState initialState() {
    return AppState(
      count: 0,
      clickCount: 0,
    );
  }

然后在入口文件中调用:

  final store = Store<AppState>(
    reducers,
    middleware: [thunkMiddleware],
    initialState: AppState.initialState(),  // 调用
  );

2. reducer 复制对象的方法

在 react/redux 中我们习惯这样写 reducer:

  const reducer = (state={
    loading: false,
    data: [],
  }, action) => {
    switch(action.type) {
      case CONST.FETCH_GITHUB_SEARCH_USER_LOADING:
        return {
          ...state,
          loading: true
        }
      case CONST.FETCH_GITHUB_SEARCH_USER_SUCCESS:
        return {
          loading: false,
          data: action.payload.items
        }
      default:
        return state
    }
  }

重点是 ...state 这样的解构写法,实际是浅复制了 state 对象,而在 dart 中没有这么方便的方法,比如 reducers.dart 中的 copyWith:

AppState counterReducer(AppState state, dynamic action) {
    switch (action) {
      case INCREMENT:
        return state.copyWith(count: state.count + 1);
      case DECREMENT:
        return state.copyWith(count: state.count - 1);
    }

    return state;
  }

copyWith 是我们自己写的扩展方法:

AppState copyWith({count, clickCount}) {
    return AppState(
      count: count ?? this.count,
      clickCount: clickCount ?? this.clickCount,
    );
  } 

?? 是条件表达式,count: count ?? this.count 表示 copyWith 只要没传进来 count 就把 AppState 实例的 count 值赋给 count,然后再实例化一个 AppState 对象。

参见其他的复制对象的方案

3. actions

比较有特点的就是 redux_thunk 的异步 action 写法:

  ThunkAction asyncIncrement() {
    return (Store store) async {
      await Future.delayed(Duration(seconds: 3)); // 延迟 3 秒

      store.dispatch(INCREMENT);
    };
  }

async / await 是不是很熟悉?

4. StoreProvider / StoreConnector

StoreProvider 很简单,就是在根组件中挂载 store:

  @override
  Widget build(BuildContext context) {
    return StoreProvider<AppState>(
      store: store,
      child: MaterialApp(
        theme: ThemeData.dark(),
        home: Home(),
      ),
    );
  } 

而 StoreConnector 就比较麻烦了,需要先定义一个 ViewModel:

  class AppStateViewModel {
    final AppState state;
    final void Function() onClick;

    AppStateViewModel({
      this.state,
      this.onClick,
    });
  }

ViewModel 中规定你要在这个组件中使用的 Store 中的数据

  class AddButton extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return StoreConnector<AppState, AppStateViewModel>(
        converter: (store) {
          return AppStateViewModel(onClick: () {
            store.dispatch(INCREMENT);
            store.dispatch(CLICK);
          });
        },
        builder: (context, vm) {
          return Padding(
            padding: const EdgeInsets.all(8.0),
            child: FloatingActionButton(
              onPressed: vm.onClick,  // trigger!
              tooltip: 'Increment',
              child: Icon(Icons.exposure_plus_1),
            ),
          );
        },
      );
    }
  }

StoreConnector 有两个方法:

  • converter: 使用给定的转换器函数将存储转换为 ViewModel,并将 ViewModel 传递给 builder 函数
  • builder: 承接 converter 返回的数据来使用

以 AddButton 组件为例,converter 返回 onClick 函数来触发 dispatch, builder 承接到这个函数,这样就能在发起 dispatch,走 redux 的流程了。


本文只介绍 redux 在 flutter 中的应用,如果你对 React 很熟,你应该能明白 redux 的意义,除了有个全局 store 外,深层组件之间通信也不是问题了,对于 flutter 这种框架也是很有意义的。

当然,数据管理方案上直接使用 redux 可能会比较重,这和 react 是类似的,小应用的话可以用全局事件来处理。但是,多人协作的大项目 redux 是你最应该想到的数据管理方案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值