欢迎您光临深圳塔灯网络科技有限公司!
电话图标 余先生:13699882642

网站百科

为您解码网站建设的点点滴滴

Flutter 状态管理

发表日期:2018-12 文章编辑:小灯 浏览次数:2677

在 React Native 要做状态管理通常都是使用 Redux,这种方式非常好。幸运的是,在 Flutter 也支持使用 Redux。

flutter_redux 是一个支持在 Flutter 里使用 Redux 的库,但并不是使用 JS 版本的 Redux,而是使用 dart_redux,这是一个在 dart 上的 Redux 实现。

Redux 的基础知识就不多说了,在这里主要介绍如何在 Flutter 里使用 Redux 管理应用的数据状态。

先安装依赖:

dependencies: redux: ^3.0.0 flutter_redux: ^0.5.2 

在 Flutter Redux 里有一个必要知道的概念:

  • StoreProvider - 一个组件,它会将给定的 Redux Store 传递给它的所有子组件。
  • StoreBuilder - 一个子 Widget 组件,StoreProvider 它从 Action 中获取 Store 并将其传递给 Widget builder 函数。
  • StoreConnector - 从最近的 StoreProvider 祖先获取 Store 的子 Widget,使用给定的函数将其转换 Store 为 Action,并将其传递给函数。只要 Store 发出更改事件,Widget 就会自动重建。无需管理订阅!

Flutter Redux 的概念就像是 react-redux 一样。

下面来看一个简单的示例。

import 'package:flutter/material.dart'; import 'package:redux/redux.dart'; import 'package:flutter_redux/flutter_redux.dart';void main() { runApp(new FlutterReduxApp()); }// 定义个 Types 枚举 enum Types { Increment }// Reducer 处理 int Reducer(int state, action) { if (action == Types.Increment) { return state + 1; }return state; }// 创建一个 Action 类 class Action { dynamic store; dynamic dispatch; Action(store) { this.store = store; this.dispatch = store.dispatch; }// 某个 Action increment() { dispatch(Types.Increment); } }class FlutterReduxApp extends StatelessWidget { // 创建一个 store Action action; final store = new Store(Reducer, initialState: 0);@override Widget build(BuildContext context) { // 初始化 action if (action == null) { action = new Action(store); }return new MaterialApp( // 创建一个 Provider home: new StoreProvider( store: this.store, child: new Scaffold( body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: [ new Text('You have pushed the button this many times:'), // 连接器,连接之后可以获取数据,在 builder 里渲染内容 new StoreConnector<int, String>( converter: (store) => store.state.toString(), builder: (context, count) => new Text(count), ) ], ), ), floatingActionButton: new FloatingActionButton( onPressed: action.increment, // action child: new Icon(Icons.add), ), ), ), ); } } 

在需要改变状态的组件里使用 StoreConnector 连接数据(避免对整个内容做一次性的连接,导致整个渲染)。

在这里 Store 是一个泛型类,在初始化时请给它一个类型,否则就是 Store<int>。很多时候 State 是一个复杂的结构,并不是一个简单的 int 类型,那么如何适配?

// Reducer 处理 State reducer(State state, action) { if (action == Types.Increment) { state.count++; return state.newState(state); }return state; }class State { List<String> list; String name; int count; State(this.list, this.name, this.count); // 返回一个新的实例 newState(State obj) { this.name = obj.name; this.list = obj.list; this.count = obj.count; return new State(obj.list, obj.name, obj.count); } }// 创建一个 store final store = new Store<State>(reducer, initialState: new State([], 'abc', 0));// 连接器,连接之后可以获取数据,在 builder 里渲染内容 new StoreConnector<State, String>( converter: (store) => store.state.count.toString(), builder: (context, count) => new Text(count), ), 

StoreConnector 里的 converter 一定要是返回 String 吗?目前为止是的,因为大多数的在 Widget 上都是使用字符串渲染。

此外,可以使用 StoreConnector 对某个组件进行数据的连接,对于不变化的组件那就没必要连接了。

在 Action 初始了一个 store 和 dispatch,这样就可以在方法里直接引用 store 和 dispatch。

// 创建一个 Action 类 class Action { Store<State> store; dynamic dispatch; Action(store) { this.store = store; this.dispatch = store.dispatch; }// 某个 Action increment() { dispatch(Types.Increment); } } 

中间件

中间件是一个非常有用的东西,它可以在 Reducer 操作之前做一些拦截或者记录工作。

Store 的第三个参数是一个接受中间件的参数,我们可以通过下面的定义中间件方式,为 Store 添加中间件。

loggingMiddleware<T>(Store<T> store, action, NextDispatcher next) { print('${new DateTime.now()}: $action'); next(action); }final store = new Store<int>( counterReducer, initialState: 0, middleware: [loggingMiddleware], ); 

异步操作

在 action 里使用 async 即可,在等待异步操作完成后再调用 dispatch。

// 某个 Action increment() async { // 模拟某个异步操作 await new Future.delayed(new Duration(seconds: 1)); // 完成后 dispatch dispatch(Types.Increment); } 

传递数据

在调用 dispatch 的时候 action 是一个 dynamic 类型,在上面是没有传递数据的,而数据的变化在 Reducer 里。

那么如何传递数据呢?在 action 里是一个 dynamic 类型,因此可以把 action 写成 Map 类型,在 Map 里获取 type 和 data。

// Reducer 处理 State reducer(State state, action) { if (action['type'] == Types.Increment) { state.count = action['data']; return state.newState(state); }return state; }// 某个 Action increment() async { // 模拟某个异步操作 await new Future.delayed(new Duration(seconds: 1)); // 完成后 dispatch dispatch({ 'type': Types.Increment, 'data': store.state.count + 1, }); } 

这样就可以把数据从 Action 传递到 Reducer 了。

精简代码

在上面的代码里,在 Action 里得到最新的状态只,在 Reducer 里又需要进行一次赋值,这样会多出很多重复的代码。现在把 Action 变成一个 newState 函数,在函数里更新最新的状态,在 Reducer 里只创建新的实例即可,这样可以节省很多代码,Types 也不需要写了。

// Reducer 处理 State reducer(State state, action) { if (action is Function) { var s = state.newState(action(state)); if (s != null) return s; } return state; }// 某个 Action increment() async { // 模拟某个异步操作 await new Future.delayed(new Duration(seconds: 1)); // 完成后 dispatchdispatch((State state) { // 要更新的状态 state.count++; return state; }); } 

不知看懂了没有,实际上就是利用传递函数与上下文的特点。


本页内容由塔灯网络科技有限公司通过网络收集编辑所得,所有资料仅供用户学习参考,本站不拥有所有权,如您认为本网页中由涉嫌抄袭的内容,请及时与我们联系,并提供相关证据,工作人员会在5工作日内联系您,一经查实,本站立刻删除侵权内容。本文链接:https://dengtar.com/17631.html
相关APP开发
 八年  行业经验

多一份参考,总有益处

联系深圳网站公司塔灯网络,免费获得网站建设方案及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

业务热线:余经理:13699882642

Copyright ? 2013-2018 Tadeng NetWork Technology Co., LTD. All Rights Reserved.