发表日期:2018-12 文章编辑:小灯 浏览次数:3105
在 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; }); }
不知看懂了没有,实际上就是利用传递函数与上下文的特点。
日期:2018-10 浏览次数:7246
日期:2018-12 浏览次数:4319
日期:2018-07 浏览次数:4868
日期:2018-12 浏览次数:4168
日期:2018-09 浏览次数:5490
日期:2018-12 浏览次数:9915
日期:2018-11 浏览次数:4797
日期:2018-07 浏览次数:4573
日期:2018-05 浏览次数:4851
日期:2018-12 浏览次数:4314
日期:2018-10 浏览次数:5132
日期:2018-12 浏览次数:6206
日期:2018-11 浏览次数:4453
日期:2018-08 浏览次数:4584
日期:2018-11 浏览次数:12622
日期:2018-09 浏览次数:5570
日期:2018-12 浏览次数:4823
日期:2018-10 浏览次数:4178
日期:2018-11 浏览次数:4522
日期:2018-12 浏览次数:6057
日期:2018-06 浏览次数:4001
日期:2018-08 浏览次数:5426
日期:2018-10 浏览次数:4452
日期:2018-12 浏览次数:4516
日期:2018-07 浏览次数:4354
日期:2018-12 浏览次数:4492
日期:2018-06 浏览次数:4375
日期:2018-11 浏览次数:4369
日期:2018-12 浏览次数:4242
日期:2018-12 浏览次数:5275
Copyright ? 2013-2018 Tadeng NetWork Technology Co., LTD. All Rights Reserved.